CONNAISSANCES DE BASE
POUR PROGRAMMER DES JEUX AVECUNITY3D (V2018)ETC#
Ces notes sont accompagnés de rapides exercices (10 mn environ, livrés avec les composants
nécessaires, le code source ne sera communiqué que sur demande, en cas de difficultés)
Extraits rassemblés et offerts par Godaille_de_Rigadeaux
Destiné aux débutants en quête de perfectionnement (déjà initiés à l’ergonomie de Unity)
Table des matières
CONNAISSANCES DE BASE......................................................................................................................................................1
POUR PROGRAMMER DES JEUX AVECUNITY3D (V2018)ETC#................................................................................................1
I – Les bases de la programmation dans UNITY :.............................................................................................................6
1) Conception générale :...........................................................................................................................................6
2) Eléments composants un script :..........................................................................................................................6
a) Variables :........................................................................................................................................................7
b) Fonctions :........................................................................................................................................................7
c) Class :................................................................................................................................................................7
a) Différences entre 2D et 3D :.............................................................................................................................8
b) Choisir et Enregistrer l’éditeur de code qui a votre préférence :...................................................................9
c) Disposition optimale des fenètres de Unity :.................................................................................................10
4) Illustration de ces principes et définitions dans le TutoNo1 :............................................................................10
a) Préparation prélable à la réalisation des exercices :.....................................................................................10
b) Eléments à ajouter à la Scene :.......................................................................................................................11
c) Enregistrer le script, et tester l’exécution de la scène :..................................................................................14
5) Commentaires :..................................................................................................................................................15
a) Quelques explications pour comprendre le tutoriel :.....................................................................................15
b) Principes de notations des variables et des objets :.......................................................................................15
c) Role des crochets - ouvrants et fermant – encadrant une boucle de code C# { } :........................................16
d) Utilité d’écrire le code dans un éditeur spécialisé :........................................................................................16
e) Différences entre les fonctions d’action et celles qui nécessitent un retour de variable :.............................16
f) Comment neutraliser une partie du code sans le supprimer :.......................................................................16
g) Afficher des messages :..................................................................................................................................16
1) Le Canvas :..........................................................................................................................................................17
a) Principaux composants UI :............................................................................................................................17
1
b) Les 3 modes de rendu d’un Canvas (« Render Mode ») :...............................................................................17
2) Création de 3 scènes : Un Menu principal et de 2 sous-menus :........................................................................18
a) Menu principal :..............................................................................................................................................18
b) Les Sous-menus..............................................................................................................................................21
c) Navigation d’un menu à l’autre :....................................................................................................................22
d) Bouton de sortie pour « Quitter le programme » :........................................................................................25
1) Gestion des données dans C # et Unity :............................................................................................................26
a) La liste.............................................................................................................................................................26
b) Le tableau (Array)...........................................................................................................................................27
c) Le Dictionnaire (dictionary)............................................................................................................................29
2) Utilisation d’une DropBox (liste déroulante d’options) :....................................................................................30
a) Etapes préparatoires :....................................................................................................................................30
b) Script de gestion de la liste :...........................................................................................................................33
3) Enregistrer les listes dans un fichier externe, puis les restaurer depuis ce même enregistrement :.................35
a) Ajouter 2 boutons (dénommé Save et Retore) :.............................................................................................35
b) Ajouter une fonction, SaveToFile,..................................................................................................................35
c) Ajouter une fonction, LoadFromFile,.............................................................................................................36
d) Relier ces fonctions à l’évènement « OnClic » des boutons de sauvegarde et de restauration :...................37
e) Avant de tester le bon fonctionnement du tutoriel,......................................................................................37
III – Améliorations de l’interface utilisateur – Tuto4 :...................................................................................................38
1) Les bulles d’aide (« ToolTips » ou « Hints ») :.....................................................................................................38
a) Créer une nouvelle scène « HintAndMsg », dans le répertoire « _TutoNo4 » :............................................38
b) Insérer 2 UI Panels, l’un désigné « Hint » et l’autre « Affichage » :................................................................38
c) Fonctionnement attendu et le script de commande :....................................................................................38
d) Insérer le script et relier les objets concernés :..............................................................................................40
e) Tester le résultat :...........................................................................................................................................40
2) La boite de cases à cocher, à sélection unique :.................................................................................................40
a) Il contiendra 8 éléments , A AJOUTER, selon les indications suivantes :.......................................................41
b) Le Script « Toggle Select » :............................................................................................................................41
c) Rattachement du script à la scène :....................................................................................................................42
3) Boutons animés et sonorisés :............................................................................................................................42
a) Créer 4 nouveaux boutons :...........................................................................................................................42
b) ajouter à la scène, un objet appelé « AudioSource » :..................................................................................43
c) Créer un script «AnimButtons » :..................................................................................................................43
d) Rattacher le script à la scène et relier les fonctions :.....................................................................................45
2
e) Tester la scène................................................................................................................................................45
4) Comment sauvegarder les 3 composants pour pouvoir les réutiliser :..............................................................46
5) Boites de message modales :..............................................................................................................................46
a) Insérer le préfab « ModalWindow », à l’intérieur du panel « Affichage » :...................................................46
b) Ajouter au script une fonction « SetupBox » destinée à personnaliser la boite de message, selon le type de
boite défini par le bouton appelant :.....................................................................................................................47
c) Compléter le script « AnimButtons » comme indiqué ci-dessous :................................................................48
d) Tester la scène en faisant apparaitre et disparaitre la boite modale :...........................................................50
IV – Déplacement d’objets (sans animation) :................................................................................................................51
1) Examen des différentes manières disponibles pour déplacer un objet :...........................................................51
a) Déplacement vers un point indiqué par un clic souris :..................................................................................51
b) Déplacement avec les touches de clavier (ou les boutons d’une manette) :.................................................51
2) Comment appliquer ce mouvement par un script :............................................................................................52
a) Accéder au paramètrage des outils de pointage (clavier, souris ou joystick) :...............................................52
b) Les fonctions à utiliser dans les scripts :.........................................................................................................54
3) _TutoNo_5 : Mise en application de ces principes :...........................................................................................55
a) Déplacement vers un point localisé par la souris :.........................................................................................55
b) Déplacement avec les touches du clavier ou une manette de jeu (JoyStick) :...............................................59
c) Déplacement avec rotation (variante du précédent) :...................................................................................62
d) Contournement automatique d’obstacle:......................................................................................................66
V – Création et animation de personnages 2D :.............................................................................................................70
1) Terminologie et généralités :..............................................................................................................................70
2) Installer les « packages » Unity nécessaires et convertir les images :................................................................71
a) Menu / Windows / Package Manager / All Packages ou Advanced jusqu’à ce qu’ils apparaissent tous
ainsi :.......................................................................................................................................................................71
b) Créer un répertoire intitulé _TutoNo6...........................................................................................................71
3) Décomposition des planches (Split) en Sprites individuels :...............................................................................72
a) Ouvrir l’éditeur de Sprite et charger la planche Coins :.................................................................................72
b) Refaire la même manipulation avec les 2 autres planches :...........................................................................74
c) Pour pouvoir créer les animations de la planche « Girl », il est préférable de renommer les Sprites en
fonction du mouvement auquel ils contribuent (« AnimationMix ») :...................................................................75
4) Combiner toutes les animations dans un « Animator Controller »........................................................................79
1) Créer un nouvel animator Controller :...............................................................................................................79
2) Paramètres et transitions :.................................................................................................................................81
a) Quitter l’onglet «Layer» pour l’onglet « Parameters»...................................................................................81
b) Transitions entre Girl_Idle et Girl_Jump :.......................................................................................................81
c) Finir le param étrage des autres transtions, en suivant ces instructions :....................................................82
3
3) Créer le Game Object « Girl_Player » :...................................................................................................................83
a) Créer une plateforme pour servir de sol :..........................................................................................................83
b) Créer le GameObject « Player_Girl »..................................................................................................................83
c) Créer un nouveau script, intitule Basic2D_Controller....................................................................................84
VI – Création de personnages 3D et leur intégration dans Unity :.................................................................................87
1) Création de personnages 3D :............................................................................................................................87
a) Les 3 outils externes les plus recommandés pour créer des personnage 3D :...............................................87
b) Utilisation de Mixamo (version en ligne dérivée de Fuse) :............................................................................87
c) Intégration du personnage dans Unity :.........................................................................................................91
VII – Exemples d’utilisation des controleurs et scripts d’animation :.............................................................................96
1) Principe du système d’animation intégré à Unity (Mecanim):...........................................................................96
2) Exemples de Controller d’animation :................................................................................................................97
a) Le plus simple (composé d’un seul clip).........................................................................................................97
b) Controller simple (plusieurs clips acessibles par script) :...............................................................................98
c) Créer une scene intitulée RootMotion :.........................................................................................................99
Puis y insérer le Prefab Terrain que nous avons, déjà, utilisé dans le TutoNo5 et le personnage Beta dont le
prefab se trouve dans \Common_Workspace\3D_Character_Fbx\Beta, tout en bas...........................................99
d) Créer une nouvelle scene intitulée MultiActions :.......................................................................................100
3) Controller mixant BlendTree et simple clip :....................................................................................................101
Créer un nouveau Controller intitulé « AdvPlayer_Mixamo », il va nous permettre d’alterner la marche, la course
et le saut, en fonction des besoins .........................................................................................................................101
4) Créer une nouvelle scene intitulée Character_3DAnimation :.........................................................................103
a) L’animation sans mouvement de caméra :...................................................................................................104
b) L’animation avec mouvement de caméra :.................................................................................................107
5) Utilisation d’une Camera de type « Orbitale » capable, à la fois, de suivre le personnage et d’examiner
l’environnement avant de le déplacer :....................................................................................................................108
a) Sources des objets réutilisés :.......................................................................................................................108
b) Créer une nouvelle scene, dénommée Character_Orbit_Cam :..................................................................108
c) Modifier la scene de la façon suivante :.......................................................................................................110
VIII – Exemples de réutilisation d’objets à des usages multiples :...............................................................................115
1) Basculer, dans une même scène, d’un mode ThirdPerson vers un mode FirstPerson et inversement :.........115
a) Dupliquer la scene precédente (Ctrl + D) et la renommer « FirstThird_Controller »,..................................115
b) Réutilisation de prefabs préparés à l’avance :..............................................................................................115
c) Examen des scripts incorporés :...................................................................................................................116
d) Comment utiliser les 2 modes dans la même scene :...................................................................................118
2) « Retargeting » ou changement de personnage avec mêmes Controllers et Scripts :.....................................121
a) Créer une scene intitulée « Retarget_4Avatars »........................................................................................121
4
b) Le Canvas contient un Titre et un TogglePanel regoupant 4 cases à cocher (une pour chaque personnage) :
122
c) L’objet Multi_Camera_Rig :..........................................................................................................................122
d) Les personnages sont identiques excepté leur Avatar qui les diférencient :...............................................124
e) Noter qu’il n’est pas nécessaire de relier l’évènementes « OnValueChange » des cases à cocher à une
fonction :..............................................................................................................................................................125
f) Tester le résultat :.........................................................................................................................................125
5
I – Les bases de la programmation dans UNITY :
1) Conception générale :
Un jeu, dans Unity, est constitué d’Objets (GameObjects) qui interréagissent entre eux, comme les
acteurs d’une pièce de théatre… Le scénario permettant de mettre en scène les GameObjects est
dénommé « Game Play ». Ces GO apparaissent et évoluent dans des fenêtres qui sont désignée
comme des « Scenes ».
Le comportements des GO est fonction des propriétés et des composants (Components) qui les
constituent. Ils sont précisés par du code, écrit dans des « scripts », incorporés, ensuite, dans la
scene.
Components et Scripts sont attachés à des GO pour réaliser un jeu. Unity exécute des boucles de
traitement qui parcourent ces données pour les mettre en action selon un ordre défini par des
séquenses d’enchainements conditionnels. On appelle « FrameRate » la vitesse d’exécution du code
et de restitution visuelle des actions sur l’écran de l’ordinateur. Plus il sera élevé, plus le jeu paraitra
fluide à l’utilisateur-joueur.
2) Eléments composants un script :
Dans la structure principale de projet (répertoire dénommé Assets), Bouton-droit-sourisèCreate
èC# Script, ajoute un élément « NewBehaviorScripts » que vous renommerez, immédiatement
« myScript » : un double-click sur cet élément permet de l’ouvrir dans l’éditeur prévu (MS Visual
Studio, Xamarin (anciennement Mono), Visual Studio Code ou simplement Wordpad). Unity a créé
la structure de base suivante (renommer, si nécessaire, la MonoBehaviour Class en myScript) :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class myScript : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
Après avoir défini, en en-tête, les bibliothèques de fonctions génériques à mettre en œuvre (précédée du
mot-clé « using ») , un Script se compose, ensuite, de 3 éléments principaux :
LesVariables: Elles servent à désigner des objets ou des valeurs, pour les mettre à disposition du
programmeur qui les appellera par leur nom.
LesFonctions: Elles servent à manipuler ou à comparer les variables par du code. Le découpage du code,
par fonctions, permet de les réutiliser, à plusieurs reprises, selon les besoins. Le script devient, ainsi, plus
lisible et moins fastidieux à vérifier.
6
LesClasses sont des moyens de structurer le code en regroupant les variables et les fonctions
dans un modèle représentant le comportement d’un objet.
a) Variables :
Le script commence, toujours, par la définition des variables à utiliser ; d’abord les variables dites
« public », puis les variables dites « private » .
Les publiques vont apparaitre, visuellement, dans la scene, lorsque le script sera attaché à un objet. Il
pourra, donc, être utilisé, éventuellement, par plusieurs objets de cette scene.
Les privées ne peuvent être utilisée que dans le script où elles sont déclarées mais par toutes les
fonctions qu’il contient.
Le second aspect primordial d’une variable est son « Type » ; ils sont très nombreux mais que l’on
peut classer ainsi :
- Valeurs simples = Text (texte), String (texte en characteres Unicode utilisés par dotNet), Int
(nombre entier), Float (nombre avec décimales), bool (Booléen True ou False) …
- Valeurs complexes = List de valeurs ou d’objets, Matrice-Array de plusieurs valeurs ou objets …
- GameObject ou Composants d’objets (Image, Light, Texture, Material, Sprite, keyCode…)
- UI Components (Canvas, Text, Button, Dropdown, Topple…)
Ces différents types seront illustrés et intégrés au long des tutoriels qui suivront cette introduction.
b) Fonctions :
Les scripts manipulent les variables à l’aide de fonctions.
Certaines fonctions sont internes à Unity, d’autres sont personnalisables et programmables :
- Fonctions internes :
2 sont générées et commentées, automatiquement, à la création d’un script (voir ci-dessus) :
Start() et UpDate().
Start sera appelée, au démarrage, si le GameObject contenant le script est activé dans la scène
avant exécution.
Update est appelée une fois par frame. Elle contient une action qui s’exécute, en continu,
comme les animations ou autres séquences du jeu qui doivent être actualisées en permanence.
D’autres fonctions existent mais il serait trop long et fastidieux de les énumérer maintenant, car
nous n’utiliserons, dans l’exercice ci-dessous, que OnMouseOver() et OnMouseExit() qui
s’exécutent lorsque le curseur de la souris passe au-dessus d’un GameObject et quand il en sort.
- Fonctions personnalisées :
Elles sont destinées à effectuer une action (comme pour la souris, si ce n’est que, dans ce cas, elles
sont, librement, conçues par le programmeur).
Mais, aussi, pour effectuer un calcul et retourner un résultat. Une fonction SimpleCalc () est utilisée
dans le projet TutoNo1 et permettra d’illustrer son emploi avec un exemple simple.
c) Class :
Les classes sont des collections de variables et de fonctions pour faciliter leurs rattachements à une
scène ou aux GameObjects qui la composent. Les scripts, comme celui que nous allons écrire, sont un
parfait exemple de Class et de l’usage qui peut en être fait.
7
3) Rappel ergonomique avant d’aborder le 1erTutoriel :
a) Différences entre 2D et 3D :
A la création d’un projet, dans Unity, il est demandé (après avoir indiqué son nom et sa
localisation), si ce sera un projet 2D ou 3D :
Ce choix n’est pas définitif car il est possible d’en changer par la suite : Edit/Project Settings :
En modifiant le « Default Behaviour Mode ».
Mais, il est, aussi, possible de basculer, ponctuellement, d’un mode à l’autre, directement,
dans l’éditeur (par un clic sur l’icone 2D de la fenêtre « Scene » :
Vue 2D :
8
Vue 3D :
Elle se distingue, notamment, par l’apparition de l’icone « Gizmo » d’orientation :
Cette bascule est, parfois utile pour optimiser la position de la Camera.
Dans le mode 2D, il est préférable de mettre à 0 la position z des objets.
b) Choisir et Enregistrer l’éditeur de code qui a votre préférence :
Edit / Preferences :
9
c) Disposition optimale des fenètres de Unity :
Je vous recommande de modifier la disposition des fenètres, dans l’éditeur de UNITY, afin
d’obtenir l’affichage (ci-dessus), puis de l’enregistrer sous le nom « maDispo », de manière à
la réutiliser dans d’autres projets.
Elle permet, lorsque l’option « Maximize On Play » n’est pas activée, dans la fenètre
« Game », de tester, simultanément, à l’exécution, les effets du code sur nos objets, dans
différentes fenètres (notamment, Scene et Game - Game et Animator - Game et Animation
ou Scene et Console).
4) Illustration de ces principes et définitions dans le TutoNo1 :
a) Préparation prélable à la réalisation des exercices :
- Créer un nouveau projet appelé « Outils et Tutoriels »,
- Rechercher le répertoire « AssetsForTutorials_GdeR_Chap1 » que vous avez téléchargé,
selon mes instructions ; il contient tous les fichiers nécessaires pour réaliser les
exercices.
- A l’aide de l’explorateur de fichiers de Windows, copier son contenu dans le répertoire
Assets de votre projet de manière à obtenir l’arborescence suivante :
10
- Copier, également, dans le répertoite _TutoNo1, le script créé précédemment
(myScript),
- Un clic droit sur ce répertoire déroule le menu de création, selon l’enchainement suivant
èCreate èNew èScene, il permet de créer une nouvelle scène que nous
dénommerons, simplement, « myScene »,
L’arborescence du projet doit se présenter, ainsi :
Vous constatez, dans la hiérarchie de la scène, que 2 objets ont été, automatiquement,
intégrés à la scène : Une caméra et une lumière directionnelle qui sont indispensable et que
nous ne modifierons pas pour l’instant.
b) Eléments à ajouter à la Scene :
- Un Cube :
Clic droit dans la scèneè3D ObjectèCubeèmodifier le nom en Cube 3D,
Dans l’inspecteur d’objet, le Cube est créé, automatiquement, avec les proprités suivantes :
11
- Renseigner la propriété « Material » du Cobe :
Glisser-Déposer le « Material » « WhiteSmooth », depuis les Assets de TutoNo1 vers le
« MeshRenderer » du Cube3D (Element 0) :
- Editer myScript et y ajouter les variables suivantes :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class myScript : MonoBehaviour
{
public int myIntNumber = 2;
public GameObject myCube;
private MeshRenderer cubeRenderer;
private float myDecNumber = 3.5f;
private string myString;
2 variables publiques et 3 variables privées.
Enregistrer, maintenant, ce script, avant de l’intégrer au Cube3D ; on peut le faire de 2 manières :
Soit par un clic sur AddComponentèScript (au bas de l’inspecteur de propriétés du Cube3D), puis
en le récupérant dans le groupe correspondant,
Soit par un Drag&drop des Assets vers l’inspecteur de propriétés.
Après l’opération, il se présente ainsi :
12
NOTER QUE SEULES LES VARIABLES PUBLIQUES SONT VISIBLES ET ACCESSIBLES !!!
- Déposer, ensuite, le Cube3D, depuis la scene, dans le champ de la variable myCube :
C’EST AINSI QUE SE FAIT LA LIAISON ENTRE LA VARIABLE DU SCRIPT ET L’OBJET VISUEL DE LA SCENE.
Comme nous allons le voir, cette liaison permettra au script de s’exécuter lors de l’utilisation de
l’objet.
- Compléter le script :
Ajouter des 3 fonctions annoncées plus haut – Compléter la fonction « Start » :
Et compléter le code de la fonction « Start » comme indiqué, ci-dessous :
13
c) Enregistrer le script, et tester l’exécution de la scène :
Après s’être assuré que la fenètre Game ait son onglet « MaximiseOnPlay » cochée – pour
un affichage en grand écran :
Sans bouger la souris, on voit un Cube blanc et un message « Debug Log » en bas à gauche
qui indique le résultat du calcul de SimpleCalc : retourFonction = 2 * 3,5 = 7 :
Si on passe le curseur de la souris sur le Cube, il devient Rouge et le message « Debug Log »
le signale :
Si le curseur sort du Cube, il devient Bleu avec un message approprié :
14
Voilà ce que l’on peut réaliser, en peu de temps et avec peu de connaissances techniques
mais il nous reste à expliquer et commenter ce premier essai :
5) Commentaires :
a) Quelques explications pour comprendre le tutoriel :
- Les objets visuels de Unity (comme le Cube3D) ont des propriétés natives qui
apparaissent, automatiquement, dans l’inspecteur d’objet.
Reprenons les principales pour mieux les définir avant de les utiliser :
MESH = Structure d’une forme 3D importées, généralement, d’un logiciel de dessin
(comme Blender, 3DSMax ou autres).
SHADER = Outil de restitution de cette forme, du programme vers la carte vidéo, pour
assurer son affichage à l’écran,
TEXTURE = Image utilisée pour donner un rendu réaliste à la forme.
MATERIAL = La matière incorporée à la texture et qui contient, en particulier, sa couleur.
MESH RENDERER = Permet, principalement, le positionnement de l’objet, à l’écran par la
fonction transform().
MESH FILTER = Filtre permettant de transmettre le Material au Mesh Renderer.
BOX COLLIDER = Cadre entourant la forme destiné à gérer les collosions avec des
obstacles (terrain, sol, objets, enemies) ou avec le rayon émis par la souris (utilisé
implicitement par les fonctions OnMouseOver() et OnMouseExit() - elles ne
fonctionneraient pas sans ce Box Collider).
- Le code permet d’instancier (créer et nommer) les objets :
Puis d’accéder à leurs propriétés selon une convention d’écriture que nous continuerons
d’approfondir dans les prochains tutoriaux :
Ainsi, l’expression :
myCube.GetComponent<MeshRenderer>().material.color = Color.red;
montre comment on accède, en cascade, d’abord au composant (Mesh Renderer) de
l’objet (Cube3D) , puis à son sous-composant (Material) afin de pouvoir modifier sa
propriété couleur (Color).
b) Principes de notations des variables et des objets :
Le nom des variables ne peut pas commencer par un chiffre et ne peut pas contenir
d'espaces. En C#, la convention pour les noms de variables est « camelCase » : le premier
mot ou syllabe commence par une lettre minuscule, les syllabes suivantes, ajoutées sans
espace ou autre séparateur, commencent par une lettre majuscule. Ex : camelCase ou
myScript…
C’est, particulièrement, le cas , pour les propriétés d’Objets, les noms des Composants et les
fonctions propres à ces entités (mais cela reste , néanmoins facultatif…).
Par contre, on différentie les fonctions personnalisées par une notation CamelCase (toutes
les syllabes commencent par une Majuscule.
15
c) Role des crochets - ouvrants et fermant – encadrant une boucle de code C# { } :
Ils sont importants pour structurer et indenter le code, s’ils sont ommis, ils générent des
messages d’erreurs qui bloquent la compilation et le test d’exécution de la scène.
d) Utilité d’écrire le code dans un éditeur spécialisé :
Comme Visual Studio, Xamarin (anciennement Mono) ou Visual Studio Code (de loin, mon
préféré, pour sa gratuité, sa rapidité et son efficacité) :
- Coloration syntaxique :
- Assistance par proposition orthographique
Pour éviter les erreurs de syntaxe très fréquentes ne serait ce qu’à cause de la sensibilité
aux Majuscules / Minuscules ; ainsi qu’à la variété des fonctions du langage C# (qui
demande un temps d’accoutumance à un débutant).
- Compilation préalable du code
Permettant de détecter les erreurs avant de tester la scène dans Unity.
e) Différences entre les fonctions d’action et celles qui nécessitent un retour de variable :
- La fonction d’action commence par « void » et se termine par une double parenthèse ().
- La fonction avec variable commence par la désigner, avant de la nommer, et de l’inclure,
entre parenthèses, comme paramètre à transmettre.
f) Comment neutraliser une partie du code sans le supprimer :
Si on veut neutraliser une ligne de code sans la supprimer, il faut taper // en début de ligne
(aussi utilisé pour commenter le code).
Si on veut neutraliser plusieurs lignes, il faut faire précéder le bloc par /* et taper l’inverse, à
la fin */
g) Afficher des messages :
Le seul moyen qu’offre UNITY, apparemment, pour afficher des messages est d’utiliser la
fonction « Debug.log » qui écrit dans la console de débogage (quand est visible !!!).
A moins de les renvoyer dans une zone de texte. C’est très insuffisant, et nous verrons, plus
tard, quelques moyens personnalisables pour faire mieux.
16
II - User Interface (UI) – 1èrepartie - Tuto2
L’interface avec l’utilisateur est essentielle, quelque soit le type de jeu à programmer (dans d’autres
outils de développements, elle était nommée IHM, pour Interface - Homme - Machine).
Elle permet au joueur de commander le jeu avec des objets dédiés à cet usage. Pour rester dans le
temps imparti, nous ne traiterons que les principaux, mais cela sera une bonne manière de se
familiariser avec le Code C# et certaines de ses fonctions essentielles.
1) Le Canvas :
Les objets de l’UI ne sont pas situés dans la scène mais dans une sorte d’écran transparent qui
serait positionné, devant elle, pour contenir les objets de dialogue avec l’utilisateur-joueur.
Avant de créer un Canvas, il faut, d’abord, changer de répertoire et utiliser _TutoNo2, dans la
hiérarchie des Assets, puis y créer une nouvelle scene nommée mainMenu, dans laquelle on
ajoutera un Canvas par bouton-droitèUIèCanvas.
a) Principaux composants UI :
Dans ce tutoriel :
- Texte,
- Image,
- Panel ou Panneau,
- Toggle ou case à cocher,
- Button ou Bouton.
Dans le suivant :
- Dropdown ou liste déroulante d’options et,
- InputField ou champ de saisie.
NOTE : Si vous insérez un de ces composants, dans la scene, avant le Canvas, celui-ci sera,
automatiquement, créé , comme parent du composant, et un gestionnaire d’évènement
(« EventTrigger ») sera, aussi, ajouté à la scene !!!
b) Les 3 modes de rendu d’un Canvas (« Render Mode ») :
- Screen Space – Overlay (par défaut) : Les composants UI sont placés devant la scène, ce qui aura
pour effet de les redimensionner, automatiquement, en cas de changement de taille d’écran ou
de résolution.
- Screen Space – Camera : Le Canvas est placé à une certaine distance de la Camera, ce qui
implique que les paramètres de la Camera modifieront, automatiquement, ceux des
composants (les proportions des objets changeront avec ceux de la Camera - si une distorsion
se crée, elle devra être réglée en modifiant le champ « Field Of View » de la Camera).
- World Space : Les composants vont réagir comme les autres objets de la scène et devront être
ajustés, manuellement et individuellement.
17
Bien que le mode 3 soit le plus personnalisable, il est, aussi, plus fastidieux à utiliser ; nous
commencerons, donc, avec le mode par défaut (Screen Space – Overlay), en choisissant le
mode (« Scale with screen size ») avec une résolution de 1600 x 900 (en fonction de celle de votre
PC).
2)Création de 3 scènes : Un Menu principal et de 2 sous-menus :
a) Menu principal :
- Panneau Titre et Logo :
Insérons , dans le Canvas, un 1er Panel (UI element), intitulé, Titre_Scene1, à l’intérieur
duquel, nous ajouterons 2 autres UI éléments : Text et Image , dénommé, respectivement,1
Titre_Label et Logo. Le texte du titre sera « Menu principal » et l’image du logo :
Logo_G_de_R.png (fourni).
Drag&Drop du material de l’image dans la propriété « Source Image » du Logo.
Après repositionnement, vous deviez obtenir ceci :
- Dans la fenetre Game de la scene :
- Dans la hiérarchie de la scene :
le « Texture Type » de « Default » en « Sprite (2D and UI) ». Click sur Apply, Un Material a été ajouté en parent de l’image. Elle
pourra, ensuite, être intégrée dans la scene.
18
Noter que le fait d’insérer ces éléments dans un Panel, offre les avantages suivants :
- On peut tout déplacer en ne déplaçant que le Panel (remonter l’ensemble en haut et au
centre de la scene).,
- On peut agrandir ou réduire la taille des objets en modifiant la propriété « scale » du
Panel (j’ai utilisé un facteur de 3).
Pour améliorer l’aspect visuel, changer la couleur de fond (background) de la propriété
Image du panneau.
Insérons, enfin, dans le même panel, une case à cocher (« UI Toggle »), nommée VoirMenu
et positionnée en bas à gauche du panneau . Dans le label, saisir « Afficher Menu » ; régler
l’échelle (« scale ») du toggle à 0,4 ; décocher la propriété isOn.
En zoomant dans la scene :
De couleur orange brique) dans lequel nous insérons 2 UI Buttons, intitulés Niveau1 et
Niveau2 (dans les sous-composants texte, taper, respectivement, « Niveau 1 » et « Niveau
2).
Ajuster leurs positionnements pour obtenir la disposition suivante :
19
L’objectif est de masquer le panneau Menu, pour ne le faire apparaitre que lorsque l’on
coche la case du « Toggle » ou disparaitre, à nouveau, quand on le décoche. Pour l’instant, il
faut décocher la case située, en haut des propriétés du MenuPanel (dans l’inspecteur) ce qui
le rendra, momentanément, invisible.
Créer un script pour gérer ce comportement :
Assets / _Tuto2 / Create / C# Script), le nommer ToggleClick, puis l’ouvrir dans l’éditeur
(Xamarin, Visual Sudio ou WordPad).
Compléter le, en suivant les instructions qui suivent :
- Supprimer les fonction OnStart() et On Update() que nous n’utiliserons pas,
- Ajouter une clause using Engine.UI ;
- Créer 2 variables :
publicToggle myToggle;
publicGameObject myMenuPanel;
- Une fonction public voidToggleSwitch() qui assurera la bascule Visible / Invisible du
MenuPanel selon que le Toggle sera Coché / Décoché :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ToggleClick : MonoBehaviour
{
public Toggle myToggle;
public GameObject myMenuPanel;
public void ToggleSwitch()
{
if (myToggle.isOn) { myMenuPanel.SetActive(true); }
else { myMenuPanel.SetActive(false); }
}
}
Enregistrer ce script et revenir dans Unity.
Créer, dans la scene, un GameObject (bouton droit / Create Empty) nommé scriptContainer
et y ajouter le script ToggleClick (par Drag&Drop):
Les variables publiques doivent être reliées aux composants correspondants, également,
par des opérations de type Drag&Drop :
La hiérarchie se présente, alors, ainsi :
20
Et les propriétés du ScriptContainer :
Il faut, encore, relier notre fonction à l’objet myToggle :
- Sélectionner l’objet et rechercher, dans l’Inspecteur l’évènement « On Value Changed » ;
- Appuyer sur le + pour remplir la liste qui est vide, par défaut.
- Déposer, par Drag&Drop, le scriptContainer, dans l’emplacement vide sous « RunTime Only ».
Vous deviez obtenir la disposition suivante :
Click sur « No Function », pour dérouler et choisir les options ToggleClick / ToggleSwitch :
Et obtenir ceci :
Il ne reste plus qu’à tester le résultat, et faire, alternativement, apparaitre ou disparaitre le
MenuPanel.
b) Les Sous-menus
Le menu principal va nous permettre de naviguer vers 2 autres scènes que nous allons, maintenant,
créer : Assets /_Tuto2èbouton droit de la sourisèCreate / Scene), et les nommer Niveau1 et
Niveau2.
« Niveau 1 » dans la propriété texte,.
- Ajouter, aussi, dans ce Panel, 2 boutons, intitulés « Avant » et « Arrière », remplacer le Sprite du 1er
par l’image Next.png et le Sprite du 2 par Previous.png (ils se trouvent dans les répertoiresème
fournis).
- Les images des sprites ne sont pas correctement proportionnées, ajuster en cochant leur propriété
« Preserve Aspect ».
21
- Modifier le texte des boutons (button par défaut) en « Retour au menu » pour le bouton « Arrière »
et, « Niveau suivant » pour le bouton « Avant ».
- Décaler ces textes, à droite ou à gauche de l’icône (Sprite) afin d’améliorer leur lisibilité.
- Ouvrir la Scene Niveau2, tout en sauvegardant la précédente. Il suffira de lui adjoindre un bouton
Les hiérarchies des 2 scènes sont les suivantes :
Tandis qu’elles se visualisent ainsi :
c) Navigation d’un menu à l’autre :
- Affecter un Numéro à chacune des 3 Scenes :
Pour cela, il faut les inscrire dans la structure du projet (« Build ») :
Ouvrir la scène mainMenu, puis File / Build Settings et Click sur « Add Open Scenes » :
22
Sans fermer la fenêtre, « Scenes in Build », passer à la scène Niveau1 puis l’ajouter, à son tour
(Add Open Scene).
Refaire de même avec le Niveau2, ce qui les classent ainsi :
Ouvrir le script « ToggleClick » (précédemment créé), et lui ajouter une clause : using
UnityEngine.SceneManagement;
- Ajouter, ensuite, une nouvelle méthode pour activer la navigation ‘ »On_Navig_Btn_Click
Comportant un paramètre indiquant le numéro d’ordre de la scène à ouvrir (Enregistrer
les modifications ou compiler le code ou tout le projet).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class ToggleClick : MonoBehaviour
{
public Toggle myToggle;
public GameObject myMenuPanel;
public void ToggleSwitch()
{
if (myToggle.isOn) { myMenuPanel.SetActive(true); }
else { myMenuPanel.SetActive(false); }
}
public void On_Navig_Btn_Click(int sceneNbr)
{
if (sceneNbr == 0) { SceneManager.LoadScene(0); }
if (sceneNbr == 1) { SceneManager.LoadScene(1); }
if (sceneNbr == 2) { SceneManager.LoadScene(2); }
}
}
- Relier la fonction aux boutons :
Dans la scène mainMenu, sélectionner le bouton « Niveau1 ». Dans l’inspecteur de
propriétés, vous trouvez l’évènement « OnClick » (dont le contenu est vide ). Cliquer sur
+, pour ajouter un évènement, puis faire Glisser-Déposer l’objet scriptContainer dans la
case située sous « RunTime Only ».
Clic sur « No Function » pour dérouler comme ci-dessous et choisir le script ToggleClick
et la méthode On_Navig_Btn_Click :
23
Pour aller vers la scène NIVEAU1, il faut indiquer, sous la méthode, son numéro (à savoir 1) :
Refaire, la même chose, avec le bouton Niveau1, mais avec la valeur entière 2.
On pourrait, déjà, tester l’effet de ce 1er paramétrage, mais, il nous reste, encore, à
coder les autres évènements : Comment passer du Niveau1 au Niveau2 ; Comment
revenir du Niveau1 au Menu principal ; et Comment revenir du Niveau2 vers le Niveau1 :
La logique reste la même :
- Ouvrir la scène Niveau1, y copier l’objet scriptContainer et relier les boutons à
leur code,
- Faire de même, avec la scène Niveau2.
Pour permettre la vérification des liaisons, voici les propriétés d’un bouton de chaque
scène, dans la hiérarchie et l’inspecteur :
menuPPal :
24
Niveau1 :
Niveau2 :
Nous constatons, à l’exécution que nous passons, sans difficulté, d’une scène à l’autre avec une
grande économie de moyen car le même script « ToggleClick » (initialement prévu dans mainMenu)
a été réutilisé dans les autres scènes…
d) Bouton de sortie pour « Quitter le programme » :
Ouvrir mainMenu et ajouter un nouveau bouton, utilisant l’image ExitIcone.png (fournie).
Utiliser, le même script, pour y ajouter une nouvelle fonction, « ExitApp() :
public void ExitApp()
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
Note : Pour quitter depuis l’éditeur, nous sommes obligés de tester la valeur isPlaying. La
fonction « Application.Quit() », seule, ne fonctionnerait qu’avec le programme compilé.
Pour terminer, il faut lier cette fonction à l’évènement « OnClick » du bouton de Sortie.
25
II - User Interface (UI) – 2èmepartie – Tuto3
Pour ne pas alourdir les tutoriaux, nous traiterons, dans cette 2èmepartie, consacrée aux Objets
UI, de la liste à options déroulante (Dropdown) et du champ de saisie (InputField), ainsi que de
l’échange de données avec un fichier texte externe (dans les 2 sens, c’est-àdire, en sauvegarde
et en restauration).
Ce tutoriel suppose, au préalable, une connaissance de la gestion des données et des boucles
logiques qui permettront de les manipuler :
1) Gestion des données dans C # et Unity :
Il existe 3 composants pour gérer les valeurs : Les listes (List) ,lestableaux dynamiques (Array) et les
dictionnaires (Dictionary). Après une courte présentation des principes, nous pourrons les mettrons
en pratique :
a) La liste
Elle permet d’enregistrer et de stocker différents types de données (text, string, int …) et de les
retrouver selon leur numéro d’ordre d’enregistrement (index allant de 0 pour le 1erà n-1 pour le
dernier – où n et le nombre d’éléments). C’est le moyen d’enregistrement le plus simple et le
moins contraignant mais pas le plus performant).
Elle utilise la clause (using System.Collections.Generic;) et se déclare et s’initialise ainsi :
List<string> listNom = new list<>() ;
Puis, on y ajoute chaque élément, par une fonction Add :
listNom.add(« Dupont ») ;
listNom.add(« Durand ») ;
listNom.add(« Martin ») ; …
Pour retrouver, un nom par son indice, il suffit d’écrire :
ceNom = listNom[0] prendra la valeur «Dupont » ([1] renverra Durand et [2] Martin.
On peut citer quelques autres fonctions utiles :
listNom.Insert(0, x) // Ajoute la valeur x à l’index 0
listNom.Remove(x) // Supprime le 1erx trouvé
listNom.RemoveAt(0) // Supprime l’élément de rang 0
listNom.Clear() ; // Vide complètement la liste
listNom.Count() // Retourne le nombre d’éléments dans la liste
if (listNom.Contains(x) == true) // Permet de tester si la valeur x est dans la liste.
Une variante de la « List » est un intermédiaire avec le tableau de valeur, comme l’indique son
nom « ArrayList » :
Elle permet de stocker des valeurs de type différents, sans avoir à les spécifier , à l’avance. Voici
l’exemple d’un inventaire comprenant un entier numérique (Int) et une chaine de cararactère
(String) :
26
ArrayList listeTableau = new ArrayList();
listeTableau.Add(1);
listeTableau.Add("one");
foreach (object obj in listeTableau) {
if (obj is int) {
Debug.Log (int)obj.ToString());
if (obj is string) {
Debug.Log(obj);
if ((obj != int) && (obj != string)) {
Debug.Log(obj. name + " n’est ni un entier, ni une chaine de
caractères, il s’agit d’un " + obj.GetType().ToString());
}
}
b) Le tableau (Array)
Ilest très similaire à la liste mais, il est déclaré avec une dimension fixe ; il permet d’accéder plus
rapidement aux valeurs, mais il est, aussi, moins souple à utiliser :
Déclaration : public string[] joursDeSemaine = new string[7]; // pour 7 éléments indexés de
0 à 6.
Remplissage : en une seule fois : joursDeSemaine = new string[] {"Lundi", "Mardi",
"Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"} ;
Ou un par un, selon l’index : joursDeSemaine [0] = « Lundi » ; …..
joursDeSemaine [6] = « Dimanche » ;
Il est possible de trier un tableau, par ordre alphabétique :
Array.sort(joursDeSemaine) ;
Puis de restituer (impression dans la console de débuggage) les valeurs triées, à l’aide d’une
boucle For, indexée sur la taille du tableau (Length) :
Array.Sort(joursDeSemaine);
for (int i = 0; i < joursDeSemaine.Length; i++)
{
Console.WriteLine(joursDeSemaine [i]);
}
Restitution dans la console, par ordre alphabétique :
Dimanche
Lundi
Mardi
Mercredi
Jeudi
Vendredi
Samedi
27
RAPPEL : On peut interrompre, avant la fin, une boucle For, avec la fonction break -
exemple pour l’arrêter le Jeudi :
If (joursDeSemaine [i]) == « Jeudi » { Break ;}
Une variante de restitution consisterait à utiliser une boucle « while », ainsi formulée :
int i = 0;
bool trouve = false;
while (i < joursDeSemaine.Length && !trouve) //I < 7 et trouve étant faux
{
string valeur = jours[i];
if (valeur == "Jeudi")
{
trouve = true;
Break ;
}
else
{
i++;
}
}
if (!trouve)
Console.WriteLine("Valeur non trouvée");
else
Console.WriteLine("Trouvé à l'indice " + i);
On aurait pu, aussi, utiliser une fonction switch..case, reposant sur l’index du tableau
for (int i = 0; i < joursDeSemaine.Length; i++)
{
Switch(i)
{
Case : 0
Console.WriteLine(« 1erjour = » + joursDeSemaine [i]);
Break ;
Case : 1
Console.WriteLine(« 2ème jour = » + joursDeSemaine [i]);
Break ;
|
|Case : Autres cas de 2 à 4 …
|
28
Default :
If () { Console.WriteLine( i.ToString() + «ème jour = » +
joursDeSemaine [i]);}
else { Console.WriteLine(« Ce jour n’existe pas » ;}
Break ;
}
}
RAPPEL : La fonction Break concerne, ici, la boucle switch-case, et pas la boucle For qui va se
dérouler intégralement.
c) Le Dictionnaire (dictionary)
Ressemble à une « List », si ce n’est qu’on retrouve les valeurs au moyen d’une Clé (Key) plutôt
qu’avec un Index :
C’est un composant très puissant que nous ne ferons qu’esquisser (Le code, ci-dessous n’est
pas intégré au tutoriel, pour l’instant, mais que nous réutiliserons, très prochainement) :
Supposons que notre jeu oppose un personnage (« Character ou Player»), à des
ennemis (« Enemies »); on va recenser les ennemis préexistants, dans la scene, et
enregistrer, dans un dictionnaire, leur nom et leur position (Vector2D ou Vector3D, suivant
le mode de jeu).
La fonction GameObject.Find est concue pour ce recensement, mais pour limiter le temps
de recherche et ne pas nous encombrer d’objets inutiles, une astuce, préconisée dans Unity,
consiste à marquer les ennemis avec un « Tag » spécifique (« Enemies» créé pour la
circonstance).
Ensuite, il suffit de déclarer le dictionnaire :
Dictionary<String, Vector3> EnemyPosition;
Une liste de GameObject et un idenfiant pour chacun d’eux :
GameObject[] listEnemy ;
GameObject eachEnemy;
La recherche et le recensement s’effectueront, ainsi (dans une fonction Start, Update ou
autre) :
listEnemy = GameObject.FindGameObjectsWithTag("Enemies");
foreach (GameObject in eachEnemy in listEnemy)
{
EnemyPosition.Add(eachEnemy.name, eachEnemy.transform.position);
}
Passons, enfin à la mise en œuvre de ces principes :
29
2)Utilisation d’une DropBox (liste déroulante d’options) :
L’exercice consiste à saisir puis à enregistrer, une liste de pions affectés à 2 joueurs.
a) Etapes préparatoires :
- Utiliser le répertoire intitulé, _TutoNo3,
o Y ajouter la scène dénommée, DropdownToFiles. Puis un UI Panel, contenant 3 zones de
Textes :
o Un Titre sur 2 lignes qui explique l’objectif de ce tutoriel :
Exercice de gestion de listes déroulantes
Echanges de données avec un fichier externe
o Un champ de message communiqué à l’utilisateur : « Message »
o Un champ pour compléter son information : « Informations »
Disposés ainsi :
Dans la hiérarchie de la scène :
Dans la fenètre Game :
30
- Ajouter une zone de saisie, « InputField »,
Placée au centre avec, de part et d’autre, 2 listes déroulantes «Dropdown », intitulées,
respectivement, Pions_Joueur1 et Pion_Joueurs2 :
Observez, la composition d’une des listes déroulantes et les options telles qu’elles
sont proposées, par défaut (nous ne nous intéresserons qu’à la gestion des
données) :
En mode exécution, un clic sur la flèche, à droite, déroule 3 options, dont la 1èreest
cochée et affichée, par défaut (Option A) :
On peut, donc, sélectionner (cocher) toute autre option disponible (elles sont
affectée d’un index : 0 pour l’Option A, 1 pour l’Option B, 2 pour l’Option C)..
Dans la hiérarchie, l’arborescence (déployée) du composant contient ces éléments :
L’ascenseur vertical ou « Scrollbar » n’est visible que lorsque la liste contient plus
d’élément que ne peut en afficher la liste.
On retrouve ces Options qui sont modifiables, dans l’inspecteur d’objet :
Il est possible d’en ajouter (+) ou d’en supprimer (-).
31
- Entre la zone de saisie et chaque liste déroulante, nous allons positionner 2 boutons
En réutilisant les sprites utilisés dans le tutoriel No2 (Button_Next et Button_Previous).
2 sur chaque cotés, ce qui fait 4, nommés :
A gauche (AddLeft et SuppLeft),
et à droite (AddRight et SuppRight) ;
ce qui donne la disposition suivante :
Après chaque saisie, on pourra ajouter la valeur dans la liste de droite (par un clic sur
AddRight) ou dans la liste de gauche (clic sur AddLeft).
Inversement, nous pourrons supprimer la valeur sélectionnée de la liste de droite
(par un clic sur SuppRight) ou de la liste de gauche (clic sur SuppLeft).
Modifions le texte de la zone « Message » pour expliquer cet objectif (en 2 lignes
centrées) :
Pour insérer une option, saisir un texte et click sur le bouton d'insertion
Pour supprimer une option, click sur le bouton de retrait
Mais, pour mettre l’action en pratique, il faut, encore, créer un script contenant une
fonction à relier à la propriété « OnClic » de chaque bouton.
32
b) Script de gestion de la liste :
Dans Assets/_TotoNo3,èBouton-droitèCreate/Script, dénommé « GestionListe », à ouvrir
dans l’éditeur de code C# (Visal Studio Code pour moi), afin d’y saisir ceci :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
public class GestionListe : MonoBehaviour
{
public Dropdown PionsJoueur1;
public Dropdown PionsJoueur2;
public InputField Saisie;
// Use this for initialization
void Start () {
PionsJoueur1.ClearOptions();
PionsJoueur2.ClearOptions();
}
public void RemoveRight()
{
PionsJoueur2.options.RemoveAt(PionsJoueur2.value);
PionsJoueur2.value = 0;
}
public void RemoveLeft()
{
PionsJoueur1.options.RemoveAt(PionsJoueur1.value);
PionsJoueur1.value = 0;
}
public void FillRight()
{
PionsJoueur2.options.Add (new Dropdown.OptionData(Saisie.text));
PionsJoueur2.value = PionsJoueur2.options.Count - 1;
}
public void FillLeft()
{
PionsJoueur1.options.Add (new Dropdown.OptionData(Saisie.text));
PionsJoueur1.value = PionsJoueur1.options.Count - 1;
}
}
En résumé, ce code contient :
- La déclaration, en variables publiques (accessibles dans la Scène), de la zone de saisie et
des 2 listes déroulantes,
- Au démarrage (Start), le vidage des 2 listes des 3 options par défaut (A, B et C) .
- Les 4 fonctions FillRight, FillLeft, RemoveRight, RemoveLeft qui ajouteront ou
supprimeront un elément à chaque liste.
33
- Intéger à un nouveau GameObject de la scène :
Dans la hiérarchieèBouton-droitèCreateEmpty, renommer le GameObject
« ScriptContainer »èDrag- And- Drop du script dans les propriétés de l’objet :
Relier, aussitôt, le champ de saisie et les 2 listes déroulantes à leurs variables :
- Relier le ScriptContainer à la fonction correspondant à chaque bouton :
Par son évènement « OnClick » (comme nous l’avons déjà fait dans les exercices
précédents) :
o AddRight :
o AddLeft :
o RemoveRight :
o RemoveLeft :
34
- Testez la Scène :
Ajoutez 3 pions de couleur Jaune au Joueur1 (PionJaune1, PionJaune2, PionJaune3), puis
3 pions de couleur Verte au Joueur2 (PionVert1, PionVert2, PionVert3).
Si, par erreur, vous ajoutez un Pion Vert au Joueur1 ou un Pion Jaune au Joueur2,
vérifiez qu’il est possible de corriger cette erreur en la supprimant …
Néanmoins, l’idéal, dans la perspective du développement de jeux serait de pouvoir
sauvegarder ces données en cas d’abandon , en cours de partie et de les restaurer,
quand on pourra la reprendre ; c’est par ces 2 opérations que nous terminerons ce
tutoriel.
Cela nécessitera 2 nouveaux boutons et l’ajout de 2 fonctions dans le précédent script.
3)Enregistrer les listes dans un fichier externe, puis les restaurer depuis ce même
enregistrement :
a) Ajouter 2 boutons (dénommé Save et Retore) :
En utilisant les 2 sprites fournis portant les mêmes noms ; ils seront disposés, ainsi et leurs
textes, associés, désigneront les actions à exécuter:
b) Ajouter une fonction, SaveToFile,
Au bas du script précédent, avec le code suivant :
public void SaveToFile()
{
TextWriter writer;
string fileName;
string TheLine;
// Sauvegarde liste des pions du joueur1
fileName = "/_TutoNo3/PionsJoueur1.txt";
writer = new StreamWriter(Application.dataPath + fileName);
for (int i = 0; i < PionsJoueur1.options.Count; i++)
{
TheLine =
PionsJoueur1.GetComponent<Dropdown>().options[i].text.ToString();
if (i < PionsJoueur1.options.Count - 1)
{
writer.WriteLine(TheLine);
}
else { writer.Write(TheLine); }
}
writer.Close();
// Sauvegarde liste des pions du joueur2
……………………….à compléter avec joueur2………….
} 35
Ce code utilise la bibliothèque System.IO (déclarée en clause « using ») avec l’objet
Stream.Writer et ses fonctions WriteLine et Write (la 1èreécrit une ligne suivie d’un retour à
la ligne, en attente le la ligne suivante, la 2ème écrit la dernière ligne avant fermeture du
fichier texte).
Le code de sauvegarde des pions du Joueur2 est à compléter, en s’inspirant du précédent.
c) Ajouter une fonction, LoadFromFile,
A la suite, avec le code suivant :
public void LoadFromFile()
{
TextReader reader;
string fileName;
string TheLine;
List<string> TempList;
// Restauration liste des pions du joueur1
fileName = "/_TutoNo3/PionsJoueur1.txt";
reader = new StreamReader(Application.dataPath + fileName);
TempList = new List<string>{};
TempList.Clear();
PionsJoueur1.ClearOptions();
while ((TheLine = reader.ReadLine()) != null)
{
TempList.Add(TheLine.ToString());
}
PionsJoueur1.AddOptions(TempList);
reader.Close();
// Restauration liste des pions du joueur2
……………………….à compléter avec joueur2………….
}
Ce code utilise la bibliothèque System.IO (déclarée en clause « using ») et l’objet
Stream.Reader et sa fonction ReadLine. Pour faciiter le debuggage, en cas de problème, les
lignes du fichier sont ajoutées à une liste temporaire « TempList », avant de remplacer les
options de la liste déroulante, en une seule ligne de code :
« PionsJoueur1.AddOptions(TempList); ».
Le code de restauration des pions du Joueur2 est à compléter, en s’inspirant du précédent.
36
d) Relier ces fonctions à l’évènement « OnClic » des boutons de sauvegarde et de restauration :
Comme nous l’avons fait, précédemment :
Save :
Retaure :
e) Avant de tester le bon fonctionnement du tutoriel,
Il faut compléter les zones de texte « Message » et « Informations » avec les explications
suivantes :
- Message (sur 2 lignes) :
Pour insérer une option, saisir un texte et click sur le bouton d'insertion
Pour supprimer une option, click sur le bouton de retrait
- Informations :
Les fichiers Pions_Joueur1 et 2 se trouvent dans le répertoire _TutoNo3
Il suffit de suivre ces instructions pour vérifier si les différents boutons produisent bien les
effets attendus.
Le tutoriel No4 qui suit va nous permettre d’expérimenter des manières plus élégantes et
conviviales d’échanger des informations avec le joueur en fonction des situations
rencontrées (Les bulles d’aide et les demandes).
37
III – Améliorations de l’interface utilisateur – Tuto4 :
1) Les bulles d’aide (« ToolTips » ou « Hints ») :
Dans un jeu, il est utile d’obtenir des informations contextuelles sur des objets qui sont disposés
dans la scène, c’est le rôle des bulles d’aide ou bulles parlantes qui s’affichent, dans les logiciels
bureautiques, sur les boutons, quand le curseur de la souris les survole (elles confirment l’action qui
peut être escomptée en les actionnant).
a) Créer une nouvelle scène « HintAndMsg », dans le répertoire « _TutoNo4 » :
Nous allons y déposer 3 Objets (Clic-droitèObject 3D), une Sphere, une Capsule et un Cube, alignés et
de couleur respective Gris, Vert et Rouge.
Pour leur affecter leur couleur, modifier leur « Material », par défaut, en faisant glisser dans l’inspecteur,
en provenance de « Common Workshop / Materials, les couleurs Light_Gray, Green et Red selon l’objet
concerné :
Une fois positionnés, integrez les à un nouveau GameObject (dénommé « Objects »). Ce qui permettra,
ultérieurement, de les déplacer ou de les rendre Visibles ou Invisibles, en une seule et même opération.
b) Insérer 2 UI Panels, l’un désigné « Hint » et l’autre « Affichage » :
Hint (désigné dans le code comme « DisplayPanel ») contiendra une zone de texte appelée « Name »
mais rendue vide, par défaut. CET OBJET DOIT ETRE DECOCHE (donc rendu invisible) dans l’inspecteur.
Affichage (désigné dans le code comme « info ») une zone de texte appelée « Message », également
vide.
c) Fonctionnement attendu et le script de commande :
Lorsque le curseur de la souris passera sur un des 3 objets, Hint indiquera, au dessus de lui, le nom de
l’objet survolé et Affichage une explication du type «La souris passe au dessus de l’objet : Untel » .
Les messages, Hint et Affichage, devront s’effacer dès que le curseur sortita d’un des 3 objets.
Créer un nouveau script intitulé « Display_UI » avec le code suivant :
38
using UnityEngine.UI;
using UnityEngine;
public class Display_UI : MonoBehaviour
{
public Text hintText;
public Text info;
public GameObject DisplayPanel;
private Ray TheRay;
private RaycastHit hitFix;
private GameObject WhichObject;
private Vector3 PosDest;
// Update is called once per frame
void Update()
{
OnMouseOver();
}
public void OnMouseOver()
{
Vector2 PosPanel;
TheRay = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(TheRay, out hitFix))
{
WhichObject = GameObject.Find(hitFix.collider.name);
hintText.text = hitFix.collider.name;
PosPanel.x = hitFix.transform.position.x;
PosPanel.y = hitFix.transform.position.y + 1.5f;
DisplayPanel.SetActive(true);
DisplayPanel.transform.localPosition = PosPanel;
hintText.color = Color.white;
info.text = "La souris passe au dessus de l'objet : " + hitFix.collider.name;
}
else {
DisplayPanel.SetActive(false);
hintText.text = "";
info.text = "";
}
}
}
Commentaire du Code :
Si le rayon (« Ray ») émis par le curseur de la souris entre en collision (« hitFix ») avec un des 3 objets
(« whichObject »), la bulle (DisplayPanel » est rendu Active (Visible) et affiche le nom de cet objet (on
récupère sa position afin d’afficher ce nom 1.5f au dessus).
Dans le même temps, le message d’information explicitera l’évènement.
39
d) Insérer le script et relier les objets concernés :
Créer un Empty Object nommé Script Container et y déposer le script « Display_UI » :
Renseigner les paramètres (Drag / Drop des composants concernés) :
e) Tester le résultat :
Et changer d’objet pour observer le changement.
2) La boite de cases à cocher, à sélection unique :
Cette boite « Toggle Panel » est un « UI Panel » qui contiendra, lui- même, une zone de texte (« Title »
expliquant son usage : Boite d'options à sélection unique) et un autre UI Panel « Toggle_Group » destiné à
recevoir les options.
Placer « Toggle Panel, en bas et à gauche de la scène (voir ci-dessous).
Une fois positionné, il faut l’intégrer, dans la hiérarchie, comme un « enfant » du panneau que nous avions
dénommé « Affichage » (Drag And Drop à l’intérieur ). Le champ texte sera nommé Titre et affichera « Boite
à options à sélection unique »
Panel (voir la structure d’arborecence figurée ci-dessous). Il faut lui affecter la propriété de groupe de cases
à optionsèAdd ComponentèUIèToggle Group.
40
a) Il contiendra 8 éléments ,A AJOUTER, selon les indications suivantes :
sélectionnée),
- « Toggle Group» contenant, lui-même, 5 Toggles : Aucune, Choix 1, Choix 2, Choix 3, Choix 4.
- Une zone de texte « UserChoice » qui prendra la valeur de l’option cochée.
b) Le Script « Toggle Select » :
using UnityEngine;
using UnityEngine.UI;
public class ToggleSelect : MonoBehaviour
{
public Toggle[] ToggleOptions;
public Text SelectedValue;
private Toggle CheckedToggle;
….void Start()
{
SelectedValue.text = ToggleOptions[0].name;
}
void Update()
{
foreach (Toggle thisOption in ToggleOptions)
{ if (thisOption.isOn) {CheckedToggle = thisOption;} }
SelectedValue.text = CheckedToggle.name;
}
}
A l’exécution, l’option par défaut est affichée (« Start »), puis à chaque trame (« Update »), on
vérifie l’ option sélectionnée pour modifier l’affichage, en conséquense.
41
c) Rattachement du script à la scène :
Ajouter le script à l’objet « ScriptContainer.
Les cases à cocher de la scène doivent, ensuite, être reliées aux options de la liste du script (après avoir
fixé leur nombre – « size » – à 5 ) :
Tester la scène :
3) Boutons animés et sonorisés :
a) Créer 4 nouveaux boutons :
Les placer, les uns sous les autres, en haut et à gauche de la scène, avec, pour chacun, le nom et le texte
suivants :
Question_Btn affichera le texte Question
Information_Btn affichera le texte Information
Warning_Btn affichera le texte Avertissement
Error_Btn affichera le texte Erreur
Ils nous serviront, au paragraphe 4, à ouvrir des boites de dialogues destinées à communiquer avec
l’utilisateur selon chaque thème (ces boites sont similaires à celles que le système Windows affiche,
souvent, intempestivement) . Elles sont modales car on ne peut plus rien faire d’autre avant d’y avoir
répondu (agaçant, mais néanmoins, indispensable pour guider l’utilisateur dans certaines circonstances).
Mais, nous allons, d’abord, animer ces boutons et leur attacher un son :
42
Un bouton est constitué d’une image et d’un texte solidaires. Pour mettre le texte, à distance, à droite de
l’image, il faut d’abord les dissocier (sortir le texte de l’arborescence), pour pouvoir le déplacer et le
redimentionner à notre convenance. Puis, il faudra le réintégrer à l’intérieur du bouton.
Changer chaque image, par défaut, en déposant, à la place l’image fournie dans le répertoire « Icones » et
dénommée « b_off ».
Après ces manipulations, vous devez obtenir ceci :
Dans la hiérarchie :
Dans la scène :
Dans le panneau « Buttons », ajouter 2 images indépendantes (au même niveau que chaque bouton) b-off
et b_on, respectivement dénommés : ImageOn et ImageOff
b) ajouter à la scène, un objet appelé « AudioSource » :
Clic-droit / Audio / audiosource, puis, dans l’inspecteur, l’icone « ButtonClick » dans la
propriété « AudioClip ».
Pour entendre le son, il suffit de tester la scène, car la case à cocher « PlayOnAwake » est
activée, par défaut. Après cet essai, il faut la décocher car le son doit être déclanché par le
clic).
c) Créer un script «AnimButtons » :
Le but consiste, à chaque clic sur l’un des boutons, à jouer le son testé, puis à changer son
image de « Off » à « On » et à remettre celui qui avait été utilisé, précédemment, sur « Off ».
La variable « CallingBtn » désignera le dernier bouton utilisé et « PreviousBtn », le bouton
précédent.
Ce qui nous amène à définir et à nommer les variables qui vont désigner les objets à manipuler :
43
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class AnimButtons : MonoBehaviour
{
public AudioSource BtnAudio;
public Sprite ImgOn;
public Sprite ImgOff;
public GameObject ModalPanel;
public Text Info;
public Text MsgTitle;
public Sprite MsgIcon;
public Text MsgText;
public Button YesBtn;
public Button NoBtn;
public Text MiddleTxt;
public Button CancelBtn;
private Button PreviousBtn;
private Button CallingBtn;
private Image ImgBtn;
Les fonctions, ci-dessous, permettent d’effectuer les actions désirées pour chacun des boutons ;
ainsi que la réinitialisation (« Reset ») du bouton précédent :
public void QuestionClic()
{
PreviousBtn = CallingBtn;
BtnAudio.Play();
CallingBtn = GameObject.Find ("Question_Btn").GetComponent<Button> ();
ImgBtn = CallingBtn.image;
ImgBtn.sprite = ImgOn;
}
public void InformationClic()
{
PreviousBtn = CallingBtn;
BtnAudio.Play();
CallingBtn = GameObject.Find ("Information_Btn").GetComponent<Button> ();
ImgBtn = CallingBtn.image;
ImgBtn.sprite = ImgOn;
}
public void WarningClic()
{
PreviousBtn = CallingBtn;
BtnAudio.Play();
CallingBtn = GameObject.Find ("Warning_Btn").GetComponent<Button> ();
ImgBtn = CallingBtn.image;
ImgBtn.sprite = ImgOn;
}
44
public void ErrorClic()
{
PreviousBtn = CallingBtn;
BtnAudio.Play();
CallingBtn = GameObject.Find ("Error_Btn").GetComponent<Button> ();
ImgBtn = CallingBtn.image;
ImgBtn.sprite = ImgOn;
}
public void ResetBtn(Button SourceBtn)
{
if (PreviousBtn == null) { CallingBtn.image.sprite = ImgOff; }
else {
CallingBtn.image.sprite = ImgOff;
PreviousBtn.image.sprite = ImgOff;
}
}
d) Rattacher le script à la scène et relier les fonctions :
Ajouter le script à l’objet « ScriptContainer ».
Chaque bouton de la scène doit, ensuite, être relié au container et aux 2 fonctions du script qui
le concernent (Clic et Reset) , comme le montre l’exemple , ci-dessous (à transposer à chacun
des 4 boutons) :
e) Tester la scène
Un clic sur chaque bouton doit modifier l’image de son icone (de Off à On) et émettre le son voulu.
Tout nouveau clic sur un autre bouton doit remettre le précédent en position Off.
Le dernier bouton activé restant bien identifiable par sa position On.
45
4) Comment sauvegarder les 3 composants pour pouvoir les réutiliser :
Chacun des 3 composants que nous venons de créer (La bulle d’aide, la boite à options et le bouton
animé sonore) pourrait être réutilisé dans un autre contexte (autre scène ou autre projet). Pour ne
pas les refaire à chaque fois, Unity permet de les sauvegardé comme « Préfab », c’est-à-dire
comme des composants « semi-ouvrés » et réutilisables par simple ajout dans une scène.
Ces préfabs sonr crées, très simplement, en déposant l’objet depuis la hiérarchie du projet dans le
répertoire Assets / Prefabs.
Aussitôt fait, la couleur de l’intitulé de l’objet passe du noir au bleu, dans la hiérarchie. Si vous êtes
amenés à le modifier, un message vous préviendra que cette modification ne sera pas répercutée
au Prefab (à moins que vous le modifiez, au préalable).
S’il utilise, une texture, un matériel, un sprite ou un script, il faudra, aussi, les reprendre dans le
nouveau projet.
5) Boites de message modales :
Le dernier exercice consiste à ouvrir, selon le bouton choisi, la boite modale de confirmation
correspondante. Elle contiendra, selon le cas 1, 2 ou 3 boutons de validation (OK - OUI ou NON –
OUI, NON, ANNULE) :
OK Pour la boite d’avertissement ou de message d’erreur,
OUI / NON Pour la boite d’information,
OUI / NON / ANNULE Pour la boite de Question
Pour faciliter ce tutoriel, j’ai préparé un Prefab dénommé « ModalWindow », incorporant un script,
« KeepOnTop » (très court et dont le seul but est de s’assurer que la boite de dialogue s’affiche, au
dessus des autres objets de le scène).
a) Insérer le préfab « ModalWindow », à l’intérieur du panel « Affichage » :
Pour garantir l’effet modal des boites de message, nous souhaitons :
- Que les 4 boutons soit inactifs quand elles sont affichées,
- Que les autres objets de la scène ne soient plus visibles à cet instant,
- Que ces 2 évènements soient réversibles dès que la boite de dialogue est fermée.
La 1èreastuce pour y parvenir est de désactiver, momentanément, la propriété « Interactable »
des 4 boutons.
La 2ndconsiste à marquer les objets à rendre invisibles avec un « Tag » que nous allons intituler
« NotModal » et affecter au :
- GameObject contenant la sphère, la capsule et le cube (« Objects ») ,
- Toggle_Panel.
Cette préparation accomplie, nous pouvons modifier le script précédent.
46
b) Ajouter au script une fonction « SetupBox » destinée à personnaliser la boite de message,
selon le type de boite défini par le bouton appelant :
public void SetupBox(string BoxType, string Content)
{
if (BoxType == "Question")
{
MsgTitle.text = BoxType;
MsgText.text = Content;
MsgIcon = QuestionIcon;
YesBtn.gameObject.SetActive(true);
NoBtn.gameObject.SetActive(true);
CancelBtn.gameObject.SetActive(true);
MiddleTxt.text = "Non";
}
if (BoxType == "Information")
{
MsgTitle.text = BoxType;
MsgText.text = Content;
MsgIcon = InformationIcon;
YesBtn.gameObject.SetActive(true);
NoBtn.gameObject.SetActive(true);
CancelBtn.gameObject.SetActive(false);
MiddleTxt.text = "Non";
}
if (BoxType == "Avertissement")
{
MsgTitle.text = BoxType;
MsgText.text = Content;
MsgIcon = WarningIcon;
YesBtn.gameObject.SetActive(false);
NoBtn.gameObject.SetActive(true);
CancelBtn.gameObject.SetActive(false);
MiddleTxt.text = "Ok";
}
if (BoxType == "Erreur")
{
MsgTitle.text = BoxType;
MsgText.text = Content;
MsgIcon = WarningIcon;
YesBtn.gameObject.SetActive(false);
NoBtn.gameObject.SetActive(true);
CancelBtn.gameObject.SetActive(false);
MiddleTxt.text = "Ok";
}
}
47
c) Compléter le script « AnimButtons » comme indiqué ci-dessous :
- Nouvelles variables publiques (à la suite des précédentes) :
public Sprite ErrorIcon;
public Sprite InformationIcon;
public Sprite WarningIcon;
public Sprite QuestionIcon;
- Nouvelles variables locales (à la suite des précédentes) :
private GameObject[] ObjectsToHide;
private string ReturnMsg;
- Une fonction Awake (à la suite) permet de remplir une liste des objets à cacher lors de
l’affichage de la boite de message :
void Awake()
{
// Find all objects to hidde when Modal box is opened (tagged as NotModal)
ObjectsToHide = GameObject.FindGameObjectsWithTag("NotModal");
//Reminder of prior button used - null when awake
PreviousBtn = null;
}
- Ajouter (sous Awake), les 2 fonctions suivantes, permettant, alternativement de faire
disparaitre ou apparaitre les autres objets lors l’affichage d’un message :
public void HideAllExceptModal()
{
foreach (GameObject go in ObjectsToHide)
{ go.SetActive(false); }
}
public void ShowAllExceptModal()
{
foreach (GameObject go in ObjectsToHide)
{ go.SetActive(true); }
}
48
- Compléter les fonctions « Clic » de chaque bouton, ainsi :
QuestionClic :
HideAllExceptModal();
CallingBtn.interactable = false;
SetupBox("Question","Etes-vous satisfait ce ce tutoriel ?...");
ModalPanel.SetActive(true);
ReturnMsg = "A l'enquête de satisfaction sur ce tutoriel ? Vous avez répo
ndu : ";
InformationClic
HideAllExceptModal();
CallingBtn.interactable = false;
SetupBox("Information","Nous constatons que vous faites des progrès")
;
ModalPanel.SetActive(true);
ReturnMsg = "Ressentez vous, comme nous, votre progresssion ? : ";
WarningClic :
HideAllExceptModal();
CallingBtn.interactable = false;
SetupBox("Avertissement","Vous allez trop vite...");
ModalPanel.SetActive(true);
ReturnMsg = "A l'avertissement, selon lequel, vous allez trop vite...
Vous avez répondu : ";
ErrorClic :
HideAllExceptModal();
CallingBtn.interactable = false;
SetupBox("Erreur","Une erreur a été constatée...");
ModalPanel.SetActive(true);
ReturnMsg = "Au message d'erreur... Vous avez répondu : ";
- Ajouter le code suivant à la fonction ResetBtn (sous le code précédent) :
//Le message est complete en function du bouton appellant :
Info.text = "";
if (SourceBtn.name == "LeftButton")
d)Tester la scène en faisant apparaitre et disparaitre la boite modale :Info.text = ReturnMsg + "Oui";
if (SourceBtn.name == "RightButton")
Info.text = ReturnMsg + "Annule";
if (SourceBtn.name == "CenterButton")
Info.text = ReturnMsg + MiddleTxt.text;
CallingBtn.interactable = true;
ModalPanel.SetActive(false);
ShowAllExceptModal();
49
IV – Déplacement d’objets (sans animation) :
1) Examen des différentes manières disponibles pour déplacer un objet :
Cet exemple est caractéristique d’un phénomène fréquent et perturbant, dans Unity : Avoir
plusieurs solutions pour faire la même chose et les voir évoluer, de version en version, souvent,
sans voir supprimer les précédentes quand elles conservent des avantages particuliers.
Pour éviter cette difficulté et respecter le caractère progressif et simple de nos exercices, nous
n’examinerons que les principales, en les classant selon leur utilité pratique :
a) Déplacement vers un point indiqué par un clic souris :
- En modifiant la position de l’objet (via son composant « Transform ») :
o Sa position absolue (dans la scène) :
monObjet.transform.position = Vector3(X, Y, Z) ; (ces 3 valeurs étant considérées
comme des nombres décimaux -du type 100f, 50f, 45f par exemple).
o Sa position relative, par rapport à un autre objet –Parent – qui le contiendrait :
monObjet.transform.localPosition = Vector3(X, Y, Z) ;
- En le faisant glisser d’un point vers un autre :
Une solution consiste à utiliser une function d’interpolation linéaire, affectée d’une vitesse :
MonObjet.transform.position = Vector3.Lerp(pointA, pointB, Time.deltaTime * speed);
Chaque point etant identifié par une variable de type Vector3.
b) Déplacement avec les touches de clavier (ou les boutons d’une manette) :
- Sans utilisation des les lois physiques de la gravitation , il est recommandé d’utiliser les
fonctions de translation et de retation :
o Translate : Affectée d’un vecteur directionnel (Vector3.right, Vector3.up ou
Vector3.forward) et multiplié par un nombre décimal représentant la distance (positif
pour aller vers l’avant, négatif pour aller vers l’arrière) :
monObjet.transform.Translate(Vector3.Forward * 10f) ;
o Rotate : Affectée de 3 angles directionnels et d’une variable d’environnement :
monObjet.transform.Rotate(xAngle, yAngle , zAngle, Space.World);
monObjet.transform.Rotate(xAngle, yAngle , zAngle, Space.Self);
World qualifie une Position absolue (par rapport à la scene), Self la position relative par
rapport à un objet parent.
- Avec utilisation de la gravité (induite par le composant « RigidBody » ajouté à l’objet).
ATTENTION : Décocher « isKinematic » et n’utiliser les fonctions que dans une procédure
« FixedUpdate » d’un script et non « Update » (sensible au tauxde rafraichissement
–FrameRate).
On utilisera, alors les fonctions « AddForce » et « MovePosition » :
monRigidBody.AddForce( Vecteur directionnel, ForceMode ); le mode peut être de 3 types :
Impulse, Acceleration ou Velocity.
monRigidBody.MovePosition(position + velocity); Velocity est un Vector3 engendré par l’appui
sur les touches clavier ou manette.
50
2) Comment appliquer ce mouvement par un script :
a) Accéder au paramètrage des outils de pointage (clavier, souris ou joystick) :
Depuis l’éditeur, un clic sur Menu/Edit / Project Settings / Input affiche ceci :
51
Voici, quelques explications extraites de la documentation de Unity (nous n’en détaillerons que quelques
points nécessaires à nos exercices) :
Chaque touche clavier, chaque touche fléchée, chaque bouton de souris ou de joystick doit y être
mentionné avec le code qui lui correspond (normalisé par Microsoft Windows et dont je rappelle, ci-
dessous, les plus utiles) :
On peut, ainsi, renseigner les valeurs « Positive et Negatibe Button », ainsi qu’une valeur alternative
pour chacune d’elles. Si cette combinaison ne suffit pas, il est possible de créer de nouveaux blocs ou
d’en dupliquer certains avant de les modifier.
52
Ces préférences (« PlayerPrefs ») sont propres à chaque projet et sont stockées dans le répertoire
« project settings » :
Et dans le fichier : « InputManager.asset » qui est modifiable avec un éditeur de texte.
RECOMMANDATION : COPIER CE FICHIER SOUS UN AUTRE NOM AVANT DE VOUS EXERCER A LE
MODIFIER, IL SERA PLUS FACILE, AINSI, DE LE RESTAURER SI NECESSAIRE OU DE LE COPIER DANS UN
NOUVEAU PROJET. CELUI NECESSAIRE AUX EXERCICES EST FOURNI.
b) Les fonctions à utiliser dans les scripts :
Il suffit, ensuite, pour commander les mouvements d’un objet de les appeler, dans un script, par l’une
des fonctions suivantes :
- getkeydown : qui servient quand on appuie sur une touche,
- getkey : qui se poursuit quand on maintient la touche enfoncée,
- getkeyup : survient lorsque l’on relache la touche.
Avec une syntaxe de ce type : Input.GetKey("down")
Plus générale que Input.GetKey(KeyCode.DownArrow) ou KeyCode.S
53
3) _TutoNo_5 : Mise en application de ces principes :
Dans ce répertoire, nous allons créer, successivement, 4 scènes, nommées :
- Conbined_Clics pour déplacer un objet vers un point désigné par un clic gauche de la
souris,
- InputToMove pour déplacer l’objet au clavier ou au joystick (sans rotation),
- Combined_Moves pour faire pivoter et déplacer un objet,
- ClicToMove_NavMesh pour déplacer, automatiquement, un objet, en contournant les
obstacles.
a) Déplacement vers un point localisé par la souris :
Créer une scène dénommée « Combined_Clics » dans laquelle nous allons tester 2 méthodes de
déplacement : La première utilisant le changement de position (« Teleportation) et la seconde, le
glissement (Interpolation).
Ajouter à cette scène :
- Le préfab (fourni dans le répertoire de même nom) intitulé « Ground »,
- Un Object3D de type Capsule que vous dénommerez « Player_Capsule » :
o Noter qu’il contient, nativement, un composant « Capsule Collider » pour gérer
les collisions (avec le sol, dans le cas présent).
o Dans la propriété « MeshRenderer »èMaterials, modifier l’élément 0, en
sélectionnant « PlayerMat » (fourni dans le répertoire Prefabs) :
o Donner la valeur « Player » à la propriété « Tag » (si elle n’existe pas, il faut la
créer par un ajout – SINON CELA NE FONCTIONNERA PAS !!!
54
- Un Composant UI Panel, dans lequel il faudra, ensuite, ajouter :
o Un composant Text intitulé « Caption » pour afficher « Choisir une méthode de
déplacement en cochant l'une des 2 cases ci-dessous : »,
o 2 composants UI Toggle nommés respectivement, Teleportation et Interpolation (et
affichant ces mêmes informations dans leur propriété Text).
Cocher la propriété «isOn » du premier et la décocher sur le second.
o Un dernier composant UI Text pour afficher « Déplacer, ensuite, la capsule en indiquant
sa destination, par un clic droit, sur le sol ».
N’OUBLIEZ PAS D’AJOUTER AUX PROPRIETES DU PANEL UN TOGGLE GROUP (èAdd
ComponentèUI Toggle Group) ET DE TIRER/DEPOSER CE PANEL DANS LA PROPRIETE GROUP
DE CHACUN DES 2 TOGGLES (pour les lui rattacher)
- Disposer ces objets comme ci-dessous (en repositionnant la Camera en conséquense) :
- Créer un script, nommé « Combined_Clics » et l’ajouter aux propriétés de l’objet
« Player_Capsule »,
55
- Compléter le script, ainsi :
using UnityEngine;
using UnityEngine.UI;
public class Combined_Clics : MonoBehaviour
{
public GameObject Player;
public GameObject Ground;
public Toggle[] Moyens;
public float moveSpeed = 100f;
public float duration = 10.0f
private bool flag = false;
private Vector3 targetPos;
private Vector3 startPos;
void Start()
{
Player = GameObject.FindWithTag("Player");
}
void Update()
{
string SelectedOption = "";
foreach (Toggle thisOption in Moyens)
if (thisOption.isOn)
SelectedOption = thisOption.name;
if (Input.GetMouseButtonDown(1))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition
RaycastHit hit; // for collision test
if(Physics.Raycast(ray,out hit)) //Check collision
{
if (Ground == GameObject.Find(hit.collider.name)) //
{
flag = true;
targetPos = new Vector3(hit.point.x, hit.point.y + 1, hit.point.z);
} else {flag = false;}
}
}
if (flag)
{
if (SelectedOption == "Interpolation")
{
startPos = Player.transform.position;
moveSpeed = 1/(duration*(Vector3.Distance(startPos, targetPos)));
Player.transform.position = Vector3.Lerp(startPos, targetPos, moveSpeed);
}
56
if (SelectedOption == "Teleportation")
{
Player.transform.position = targetPos;
}
}
}
}
- Une fois le script déposé dans les propriétés du Player_Capsule, il faut relier les variables
publiques du script aux objets de la scene :
Le script peut être commenté, ainsi :
o Instantiation de l’objet Player » en Start(), la suite du code se poursuit en Update()
o Recherche de l’option cochée et récupération de son nom en Selected_option,
o Si le bouton droit de la souris est enfoncée et que ce clic est effectué sur le sol, marquer
l’évènement en passant la valeur « True » à un signet (« Flag »), et enregistrer les
coordonnées du point dans le « Vector3 », nommé « targetPos ».
o Selon l’option cochée, changer la position du Capsule_Player ou le faire glisser vers le
point de destination (targetPos).
- Tester la scène pour vérifier le déplacement attendu, selon l’option choisie:
Vous constatez que la fonction « Transform.translate » entraine un déplacement instantané de
la Capsule, ce qui équivaud bien à une téléportation (cette faculté sera très pratique dans
certains jeux, en cas de perte d’une vie du personnage ou d’un changement de niveau de jeu).
L’interpolation lin éaire produit bien un glissement accéléré au départ et ralenti à l’approche du
point de destination, avant de s’y arreter.
57
b) Déplacement avec les touches du clavier ou une manette de jeu (JoyStick) :
- Dans la scene InputToMove, ajouter les objets suivants :
o Un UI Text pour afficher l’objectif de l’exercice (sur 2 lignes) :
« Utiliser les touches du clavier, indiquées, pour déplacer la Capsule »
« ou remplacer les, momentanément, par d'autres (touches fléchées, par exemple) »
o Le Prefab « Terrain » fourni dans le répertoire du même nom (en le faisant glisser dans la
Scene).
o Faire, aussi, glisser le prefab « Dynamic _Panel » (fourni) dans l’objet Canvas.
o GameManager qui récupère et nomme les touches prévues dans les Paramètres du
projet (Project Settings ), aussi dénommées Préférences Utilisateur (PlayerPrefs).
o MenuScript relaye pour l’envoyer vers les champs du Panel de la Scène (pour les
afficher et, éventuellement, les modifier le temps d’ouverture du jeu.
Ces 2 scripts se trouvent dans le répertoireè\Assets\_TutoNo5\Prefabs\Scripts_Studica
ATTENTION : L’ORTHOGRAPHE DES NOMS DES VARIABLES DOIVENT ETRE IDENTIQUES, A CELLES
DEFINIES DANS LE GAMEMANAGER (y-compris les majuscules/ minuscules).
- Déplier et observer l’arborescence de la Scene :
58
Le terrain est composé du sol précédent (Ground) qui est bordé sur ses 4 côtés de murs invisibles
(de simples Cubes avec des BoxCillider), pour arreter la Capsule et lui éviter de tomber en
sortant des limites.
Le « Dynamic_Panel » contient les champs d’affichage ou de modification des touches de
déplacement, ainsi qu’un GameObject dénommé _GM, contenant le script « Game Manager ».
Dans les propriétés du « Dynamic_Panel », vous trouverez, aussi, le script « menuScript ».
Pour ne pas alourdir le tutoriel, ces 2 scripts figurent en annexe et ont été, simplement,
« francisés » à partir de ceux de Studica.
Noter le rattachement des scripts à l’évènement « OnClick » de chaque bouton des touches :
- Placer la Camera pour obtenir cette présentation :
- Créer un script et lui donner le même nom que celui de la scene (InputToMove ).
59
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class InputToMove : MonoBehaviour {
public GameObject KeyPanel;
void Start()
{
KeyPanel = GameObject.Find("Dynamic_Panel");
KeyPanel.SetActive(true);
}
void Update ()
{
// La fonction "GetKey" recupere les codes definis dans le script "GameManager"
// qui, lui-même, va les chercher dans les "Project Settings" pour les transmettre à la Scene
via le script "Inputmenu"
if(Input.GetKey(GameManager.GM.forward))
transform.position += Vector3.forward / 5;
if( Input.GetKey(GameManager.GM.backward))
transform.position += Vector3.back / 5;
if( Input.GetKey(GameManager.GM.left))
transform.position += Vector3.left / 5;
if( Input.GetKey(GameManager.GM.right))
transform.position += Vector3.right / 5;
if( Input.GetKeyDown(GameManager.GM.jump))
transform.position += Vector3.up;
}
}
Ce code suffit à commander les mouvements, au clavier, de la Capsule (grace aux autres scripts,
gracieusement, mis à disposition par Studica qui doit être mentionné en cas d’utilisation.
- Tester la scène et essayer les modifications suivantes : Après un clic gauche sur un champ, taper
la touche que vous souhaiter lui substituer :
60
c) Déplacement avec rotation (variante du précédent) :
La capsule se déplaçait, précédemment, d’avant en arrière et latéralement ; nous allons faire en
sorte qu’elle tourne dans la direction du mouvement, avant d’amorcer son déplacement. Pour que
sa rotation soit visible, nous lui avons ajouté un cube, semblable à la visière d’une casquette.
Nous allons expérimenter ces mouvements de 2 manières différentes selon que l’on fasse usage ou
non de la gravité (Lois physiques de la gravitation).
Comme précédemment, le choix s’effectuera en cochant l’une des 2 cases visibles , « Toggles »,
fonctionnant en groupe (si l’une est cochée, l’autre ne l’est plus)
- Ouvrir, comme précédemment, la scène suivante intitulée « Combined_Moves » , et lui ajouter
les objets suivants :
o Le prefab « Terrain » (déjà connu),
o Un UI Panel dans lequel nous tirerons l’objet « Static_Panel » (fourni comme Prefab),
o Le Prefab « Player » composé d’une Capsule assortie, à la hauteur et au-devant, de ce
qui pourrait être sa tête, d’un paralépipède rouge.
- L’arborescence dépliée de la Scene doit être semblable à celle-ci :
61
- Placer la Camera pour obtenir cette présentation :
Le texte, en vert, est un champ de contrôle pour vérifier le bon comportement des Toggles qui
conditionnera l’exécution du code approprié.
- Créer un script et lui donner le même nom que celui de la scene (Combined_Moves) :
public class Combined_Moves : MonoBehaviour
{
// Sans gravité
public GameObject Player;
public float moveSpeed = 20f;
public float jumpSpeed = 80f;
public float turnSpeed = 100f;
private Vector3 Player3DPos;
private float timeStep;
private bool isTurningLeft;
private bool isTurningRight;
// Avec Gravité
public Text Verification;
private Rigidbody rbody;
// Les 2 combinés
public Toggle[] Moyens;
private bool useGravity = false;
// Start is called before the first frame update
void Start()
{
Player = GameObject.Find(Player.name);
Player3DPos = Vector3.zero;
timeStep = Time.deltaTime;
// Avec Gravité
rbody = Player.GetComponent<Rigidbody>();
} 62
public void ToggleClic()
{
foreach (Toggle thisOption in Moyens)
if (thisOption.isOn)
{
if (thisOption.name == "Move_Axis") useGravity = false;
if (thisOption.name == "Move_Body") useGravity = true;
}
}
// FixedUpdate is called once per frameRate
void FixedUpdate()
{
if (!useGravity)
{
Verification.text = "Info : Vous n'utilisez pas la gravité... Essayez de change
r d'option ...\n";
Verification.text = Verification.text + "La différence n'est presque pas visibl
e, sauf au niveau du saut et du code !!!";
Player3DPos = Vector3.zero;
Player3DPos.x = Input.GetAxis("Horizontal");
Player3DPos.z = Input.GetAxis("Vertical");
if (Player3DPos != Vector3.zero)
transform.forward = Player3DPos;
timeStep = Time.deltaTime;
isTurningLeft = Input.GetKey(KeyCode.LeftArrow);
isTurningRight = Input.GetKey(KeyCode.RightArrow);
if (isTurningLeft && !isTurningRight)
{
Player.transform.Rotate(-Vector3.right * turnSpeed * timeStep );
Player.transform.Translate(0,0,-Player3DPos.x);
}
else if (!isTurningLeft && isTurningRight)
{
Player.transform.Rotate(Vector3.right * turnSpeed * timeStep );
Player.transform.Translate(0,0,+Player3DPos.x);
}
if ( Input.GetKeyDown(KeyCode.Space))
{
transform.position += Vector3.up * jumpSpeed * timeStep;
}
if (Player3DPos.z > 0)
transform.Translate(Player3DPos * moveSpeed * timeStep);
if (Player3DPos.z < 0)
transform.Translate(-Player3DPos * moveSpeed * timeStep);
}
63
if (useGravity == true)
Tester la scène :{
Verification.text = "Info : Vous utilisez la gravité ... Essayez de changer d'o
ption ... \n";
Verification.text = Verification.text + "La différence n'est presque pas visibl
e, sauf au niveau du saut et du code !!!";
if ( Input.GetButtonDown("Jump"))
{
rbody.AddForce( 0f, jumpSpeed / 5, 0f, ForceMode.Impulse );
}
else {
Player3DPos.x = Input.GetAxis("Horizontal");
Player3DPos.z = Input.GetAxis("Vertical");
if (Player3DPos != Vector3.zero)
rbody.transform.forward = Player3DPos;
}
rbody.MovePosition(rbody.position + Player3DPos * moveSpeed * timeStep);
}
}
}
Comme nous en avions exposé les principes, ce script offre 2 méthodes de déplacement à l’aide des touches
de clavier : :
- Sans utiliser la gravité, le déplacement s’effectura par la procédure « Transform.translate » dans un sens
positif ou négatif sur l’axe x (droite ou gauche) ou sur l’axe z (avant ou arrière). La rotation par la procédure
« Transform.rotate » dans le sens défini par Vector3.right signé positivement ou négativement. Le saut est
géré par la procédure « Transform.position » et Vector3.up.
- En utilisant la gravité, ce sera plus concis : rbody.AddForce pour le saut et rbody.MovePosition pour la
rotation et le mouvement.
N’OUBLIEZ PAS
1 – D’ATTACHER LE SCRIPT A L’OBJET PLAYER
2 - DE RELIER LES VARIABLES PUBLIQUES DU SCRIPT AVEC LES OBJETS VISUELS DE LA SCENE :
3 – D’AJOUTER UN EVENEMENT « ON CHANGE VALUE » AUX 2 TOGGLES POUR MODIFIER LA
METHODE DE MOUVEMENT :
64
- Il reste à tester la bonne exécution de la scène et comparer les 2 méthodes que nous
retrouverons lors du déplacement de personnages animés en 3D :
d) Contournement automatique d’obstacle:
Il existe un moyen très facile, dans Unity, pour mermettre à un objet de se déplacer vers un point
(indiqué par un cllic sur le sol), en contournant les obstacles et en utilisant le chemin le plus court pour y
parvenir .
Il s’agit de définir une « Surface de navigation » (« NavMesh » en anglais), voici une scène qui en montre
le paramétrage et les capacités :
- Utiliser la scène intitulée « ClickToMove_Navmesh ». Y insérer, le prefab dénommé « Terrain »
(fourni),
- Ajouter un Object3D de type Sphere (le désigner « Player ») et affecter à sa propriété « Material
– Element 0 », le material « Green ».
Clic droit sur SphereèLightèPoint Light , pour insérer un halo de lumière devant la sphère,
affecter au point lumineux la couleur « Jaune ».
- Inserer sur le sol, devant la shere, 4 Cubes (3DObject), destinés à servir d’obstacles de largeur
différentes (Scale X). Attribuer à chacun un material différent :
o Cube scale X = 5 Material – Element 0 PinkSmooth
o Cube1 scale X = 10 Material – Element 0 YellowSmooth
o Cube2 scale X = 3 Material – Element 0 OrangeSmooth
o Cube3 scale X = 15 Material – Element 0 Turqoise_smooth
- Regrouper ces 4 cubes dans un nouveau GameObject (Create Empty) dénommé « Obstacles ».
65
- Ajuster la disposition et la position de la camera pour obtenir une disposition comme celle-ci :
- Sélectionner le terrain (pas le ground), puis, par le menuèWindowsèAIèNavigation ,
afficher ceci :
Dans la boite « NavMesh Display », cocher « Show NavMest et HeightMesh ». Remarquer que le sol a
changé de couleur – de marron à bleu clair.
Un onglet Navigation a été ajouté à la droite de l’Inspecteur :
66
Dans le sous-menu Object, Cocher les 3 éléments comme ci-dessus : Il est autorisé de marcher sur le
sol , il est immobile et il est pratique de surligner les contours.
Dans le sous-menu « Bake » et appuyer sur le bouton portant le même nom.
- Sélectionner les 4 Cubes, en gardant la touche Ctrl-droite en foncée multi-sélection), et
procéder, exactement , comme précédemment, A LA DIFFERENCE QU’ON NE PEUT PAS
MARCHER sur ces obstaclesè« Not walkable » doit être sélectionné. N’oublier pas le clic sur
BAKE dans le sous-menu correspondant, ce qui aura l’effet visuel suivant :
Les obstacles sont surlignés et un socle sombre est apparu à leur base.
- Ajouter à l’objet Player (la sphère), un composant « NavMesh Agent » : « Add Component /
Navigation / NavMesh Agent »).
- Créer un script nommé intitulé « ClicToMove_NavMesh » avec le code suivant :
using UnityEngine;
[RequireComponent (typeof (UnityEngine.AI.NavMeshAgent))]
public class ClickToMove_NavMesh : MonoBehaviour {
RaycastHit hitInfo = new RaycastHit();
UnityEngine.AI.NavMeshAgent agent;
void Start () {
agent = GetComponent<UnityEngine.AI.NavMeshAgent> ();
}
void Update () {
if((Input.GetMouseButtonDown(0)) || (Input.GetMouseButtonDown(1))) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out hitInfo))
agent.destination = hitInfo.point;
}
}
}
Le code est très simple, il suffit de déclarer une variable « Agent » de type AI.NavMeshAgent », puis de renseigner
que sa destination correspond au point que nous aurons indiqué par un clic de souris quelque soit le bouton droit ou
gauche)
67
- Ajouter le script aux propriétés de l’objet Player ».
Cele devrait suffire et permettre de tester la Scène, par un clic derrière un des obstacles, vous
observerez le comportement de la Sphère : Elle va contourner les obstacles, automatiquement, pour
parvenir à destination, par le chemin le plus court.
Ce comportement autonome a été classé AI (Artificial Intelligence) car nous n’avons rien eu à coder pour
obtenir un tel effet. Cela sera précieux pour animer des ennemis qui tenteront d’attaquer notre personnage
lors de la création d’un jeu.
68
V – Création et animation de personnages 2D :
1) Terminologie et généralités :
Les objets utilisés, dans un jeu en 2D « classique », sont des images au format « png - portable network
graphic » qui sont transformées en « Sprites » quand elles sont intégrés dans Unity.
Ces images sont stockées, soit dans des fichiers individuels, soit dans des planches intitulée « SpriteSheet ».
Elles sont, généralement créés dans des outils de dessin spécialisés :
- Soit des outils généralistes comme PaintShop, PhotoShop, Blender …
- Soit des outils spécialisés dans l’infographie de jeux (gratuits ou payants) comme PyxelEdit,
Sprite Sheet Tollbox …
- Soit des outils intégrés à Unity.
Une fois les images disponibles, il faut les animer et, de la même manière, on trouve des outils spécialisés
(Spriter, Spine, Creature, ProMotion …), soit des outils intégrés à Unity.
L’objet de ces tutoriels restant la programmation, nous nous contenterons d’examiner, TRES SOMMAIREMENT,
soit les outils internes à Unity, soit l’importation des dessins et animations déjà réalisés et disponibles.
De nombreux sites offrent des biliothèques de Sprites ou SpriteSheets, gratuits ou payants ; exemple :
OpenGameArt.org ou GameArt2D.com d’où proviennent les ewamples que nous allons utiliser
Enfin, il y a 2 manières d’animer des « Sprites 2D » :
- Soit par le procédé dans les 1ers dessins animés (succession rapide d’images décomposant le
mouvement),
- Soit en appliquant le mécanisme conçu pour les objets 3D (attacher un squelette au dessin, puis
en déplacer les membres, dans une séquense déterminée, et à une vitesse ajustées sur un
diagramme de temps (« TimeLine »).
Chaque séquense d’animation est appellée « Clip » ou « Vidéo Clip », le terme « Animation » étant réservé à un
mouvement complet réalisé par un enchainement de « Clips ».
L’expression générique « Sprite » est, plus précisément, utilisée pour les personnages (« Characters »), on parle
de « Tiles » quand il s’agit d’objets d’environnement statiques, ou de « Background » quand il s’agit d’images
d’arrière plan.
Il existe, aussi, des outils pour faciliter la composition d’un scene 2D, à la manière d’un mécano, en plaçant les
« tiles » sur une grille qualifiée de « TileSet » ; nous en verrons un exemple rapide.
69
2) Installer les « packages » Unity nécessaires et convertir les images :
Ou vérifier s’ils sont déjà, installés :
a) Menu / Windows / Package Manager / All Packages ou Advanced jusqu’à ce qu’ils
apparaissent tous ainsi :
Les 4 premiers packages doivent être installés (marqués d’une conche à gauche). S’ils ne n’étaient pas, clic
sur Install, pour chacun d’eux, en commençant par le haut, puis en descendant sur les suivants, dans l’ordre.
b) Créer un répertoire intitulé _TutoNo6
- Y copier les répertoires Sprites et SpriteSheets fournis,
- Le répertoire SpriteSheets contient, lui-même, 2 sous répertoires Sprites et Tiles :
Néanmoins, vous pouvez constater une différence dans leur contenu respectif : Les SpriteSheets
du répertoire Tiles ont déjà été décomposés en sprites individuels alors que ce n’est pas le cas
du répertoire Sprite :
Il va falloir le faire pour les planches Coins et Girl, en utilisant l’éditeur de Sprite intégrés à Unity(Mist
est, aussi, fourni, pour vous exercer mais nous ne l’utiliserons pas).
70
3) Décomposition des planches (Split) en Sprites individuels :
Nous allons le faire en testant les différentes méthodes offertes par l’éditeur :
a) Ouvrir l’éditeur de Sprite et charger la planche Coins :
Une fois sélectionnée dans les Assets, l’inspecteur de propriétés affiche ceci, par défaut :
Modifier Texture Type, en choisissant (Sprite (2D and UI) dans la liste déroulante, le contenu change,
aussitôt, ainsi :
71
Modifier le Sprite Mode de Single àMultiple(puisqu’il s’agit d’une planche), puis appuyer sur le bouton
« Sprite Editor » :
Dans la fenêtre d’avertissement qui s’ouvre, valider « Apply » pour Continuer :
L’éditeur s’ouvre et affiche la planche :
Comme l’espacement entre chaque image est identique, nous allons tenter de les découper,
automatiquement, par la fonction Slice, de type « Automatic », paramétrée ainsi :
Les pièces sont encadrées, proportionnellement, à leur taille :
Valider par un click sur Apply (en haut, à droite) :
Pour chaque cadre, une information de dimension s’affiche :
72
Fermer l’Editeur pour constater le changement dans les Assets : Il affiche, maintenent, les positions des
pièces :
b) Refaire la même manipulation avec les 2 autres planches :
Mais en adaptant le Type de Slicing et son paramétrage, aux caractéristiques de chaque planche :
- Mist : Le type « Automatique » pourra, encore fonctionner, car la planche peut être découpée
régulièrement, même si les images n’ont pas la même dimension. Vous devez obtenir une
décomposition en 36 Sprites :
73
- Pour la planche Girl, les images ne sont ni proportionnées, ni régulières :
Avec le même type « Automatique », il va falloir dessiner, manuellement, un cadre autour de chaque
Sprite, pour pouvoir le découper. C’est long et fastidieux mais possible, en ajustant chaque cadre avec
les poignées bleues (cela ne fonctionne pas avec les vertes).
Un aperçu, en cours de travail :
Et le résultat final :
c) Pour pouvoir créer les animations de la planche « Girl », il est préférable de renommer les
Sprites en fonction du mouvement auquel ils contribuent (« AnimationMix ») :
Pour vous faciliter la tache, j’ai fait un tableau de correspondances, mais , je vous rassure nous
n’effectuerons que la 1ere opération, c’est-à-dire les 3 1eres lignes, qui nous serviront d’exercice.
Je vous livrerai, ensuite, les fichiers obtenus après complète réalisation !!!
74
Pour bien ranger les résultats, ill nous faut créer un sous répertoitre pour les animations ( dans les
Assets du Projet, créer un Répertoire Animation » et un sous-répertoire « Girl », au cas où il y aurait
d’autres personnages à animer).
Sélectionner simultanément (en maintenant la touche Controle En foncée), les sprites correspondant au
« Mix JumpLeft » et les déposer dans la scène, il vous sera demandé de désigner un répertoire et un
nom ; Saisir « JumpLeft.anim » et Enregistrer.
Vous constatez qu’une animation, par défaut, « SpriteSheet_Girl1 » a été insérée dans la scene, et un
animation controller de même nom dans /Assets/Animation/Girl.
Vérifier l’animation en testant la scène.
Renommer le fichier dans /Assets/Animation/Girl avec un nom plus explicite « JumpLeft » (ce clip
d’animation pourra être réutilisé en cas de besoin).
75
En résumé, Unity a simplifié pour nous, dans une même opération, la création d’un Vidéo-Clip et d’un
Animation Controller :
- Pour visualiser le vidéo-Clip, le sélectionner dans les Assets, l’inspecteur d’objet se présente
ainsi :
- Si aucun sprite n’apparait dans la zone animation, y déposer SpriteSheet_Girl1 depuis la scène.
Appuyer sur l’icone pour tester l’animation.
- Pour vérifier sa composition, la sélectionner puis , par le Menu / Windows / Animation /
Animation, on affiche l’animation, dans une échelle de temps (tourner vers le bas la fleche
devant Sprite pour en dérouler le contenu) :
- Sélectionner l’animation Controller, depuis les Assets (il porte le même nom mais son icone est
différente). Appuyer sur « Open » depuis l’inspecteur :
76
Normalement, il faudrait recommencer cette opération, en suivant, la grille ci-dessus : JumpRight,
ClimbLeft, ClimbRight, Idle, RunRight, WalkRight, RunLeft, WalkLeft.
Comme c’est fastidieux pour un apprentissage, nous allons récupérer les fichiers dans des
répertoires que j’ai mis à votre disposition.
Avant de le supprimer, observez l’objet qui a été inséré dans la scène : « SpriteSheet_Girl1 », et ses
propriétés :
L’ « Animator Controller », déjà cité, a été ajouté (il contient le premier « Video-Clip »). Il est
possible d’en changer ou d’en combiner plusieurs dans un script.
Vider maintenant, les répertoires des Assets, « Animation / Girl », et « Sprites / Girl » (ou créer les
s’ils n’existaient pas encore) et recopier dedans le contenu des répertoires fournis « Animation Girl
OK » et « Sprite Girl OK ». Nous serons, ainsi, assurés de poursuivre avec des données identiques.
77
4) Combiner toutes les animations dans un « Animator Controller »
1) Créer un nouvel animator Controller :
Assets / Animation / Girl + Clic-droit Create / Animator Controller, le nommer « _Full_Anim_Girl » (le 1er
caractère permet de s’assurer qu’il soit en tête d’une liste qui est déjà bien pleine) :
Un nouvel Onglet Animator est apparu à la droite de la fenêtre Scène (mais rien n’a été ajoutée à la scène
elle-même) :
Nous allons y ajouter les précédents Animator Controller pour les combiner dans une animation générale :
La 1ere animation à insérer est, le plus souvent, nommée « Idle » (celle où le personnage est inactif / oisif) :
Drad And Drop de « Girl_Idle_Right » dans le cadre « Base Layer » :
Essayez de disposer les objets comme je le montre, cela facilitera les empilages successifs (Zoom avec la
molette de la souris, drag and drop, multisélection etc …).
Une transition, automatique et obligatoire, est crée entre « Entry » et ce premier élément.
Il est utile qu’ « Any State » soit aussi relié (nous le ferons à la fin des transitions).
78
Dans l’inspecteur de propriétés :
Modifier le nom pour le rendre plus concis (Remarque : Je ne vais utiliser que des mouvements vers la droite,
car nous le verrons que le scrip se chargera de faire tourner notre personnage).
Insérer, successivement, «Girl_Jump_Right, Girl_Climbing, Girl_Wallk_Right » (les renommer Girl_Jump,
Girl_Climb et Girl_Walk); puis disposer l’ensemble, comme ci-dessous :
79
2) Paramètres et transitions :
a) Quitter l’onglet «Layer» pour l’onglet « Parameters»
Ajouter les valeurs suivantes (Clic sur le signe +) :
Speed Float
Grounded Bool
Climbing Bool
b) Transitions entre Girl_Idle et Girl_Jump :
Sélectionner Girl_Idle + Bouton-droit / Make transitionèune flèche apparait, la déposer, d’un clic,
sur Girl_Jump.
Faire l’inverse, sélectionner Girl_Jump + bouton-droit / Make transition et déposer la flèche d’un
click sur Girl_Idle.
Sélectionner la transition Girl_Idle vers Girl_Jump, l’inspecteur de propiété montre ceci :
80
Ajouter une condition : « Grounded equals false »
c) Finir le param étrage des autres transtions, en suivant ces instructions :
- Girl_Idle ç èGirl_Climb Condition Climbing Equals True or False
- Girl_Idle ç èGirl_Walk Condition Speed > or < 0.1
81
- Girl_WalkèGirl_Jump Condition Grounded Equals False
Mais sans retour : On peut Sauter en courant mais on doit repasser par le sol pour recourir !!!
- Créer une transition de “Any State” vers “Girl_Idle” avec la condition Grounded Equals True.
Le visuel final de l’animator Controller est le suivant :
3) Créer le Game Object « Girl_Player » :
Notre scène est vide (en dehors des composants par défaut - Camera et Light) :
a) Créer une plateforme pour servir de sol :
- Hierarchy + clic-droit / Create Empty ; renommer en Ground_Platform ,
- Add Component / Rendering / SpriteRenderer,
- Add Component / Physcic2D / BoxCollider (pour éviter que notre personnage ne passe au travers
du sol),
- Drap And Drop / Spritesheet / Tiles / Platform_tiles du sprite “3” vers le SpriteRenderer de
“Ground_Platform”.
- Scale x = 50, y =1, z=0
b) Créer le GameObject « Player_Girl »
- Hierarchy + clic-droit / Create Empty ; renommer en Player_Girl ,
- Add Component / Rendering / SpriteRenderer,
- Drap And Drop / Sprites / Sprites / Girl / IdleRight vers le SpriteRenderer de “Player_Girl”
- Add Component. / Physics2D / RigidBody,
- Add Component /Physics2D / Capsule Collider.
- Add Component / Miscelaneous / Animator et y placer _Full_Anim_Girl
82
c) Créer un nouveau script, intitule Basic2D_Controller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Basic2D_Controller : MonoBehaviour
{
public GameObject Player;
private Rigidbody2D rb;
public int moveSpeed = 5;
public int jumpForce = 12;
private bool isGrounded;
private Animator anim;
private float moveVelocity;
private Transform target;
private BoxCollider2D boxCollider;
// Start is called before the first frame update
void Start()
{
Player = GameObject.Find("Player");
rb = Player.GetComponent<Rigidbody2D>();
anim = Player.GetComponent<Animator> ();
boxCollider = Player.GetComponent<BoxCollider2D>();
isGrounded = true;
}
Au départ (On Start), il faut déclarer le personnage(Player) et ses composants utiles au mouvement (RigidBody), à
l’animation (Animator) et à la gestion des Collosions (coxCollider).
83
// Update is called once per frame
void FixedUpdate()
{
moveVelocity = moveSpeed * Input.GetAxisRaw ("Horizontal");
rb.velocity = new Vector2 (- moveVelocity, rb.velocity.y);
anim.SetFloat ("Speed", Mathf.Abs(rb.velocity.x));
if( Input.GetKey(KeyCode.LeftArrow)) {
rb.transform.localRotation = Quaternion.Euler(0, 180, 0);
rb.transform.Translate(- Vector3.left / moveSpeed);
}
if( Input.GetKey(KeyCode.RightArrow)) {
rb.transform.localRotation = Quaternion.Euler(0, 0, 0);
rb.transform.Translate(Vector3.right / moveSpeed);
}
if (Input.GetButtonDown ("Jump") && isGrounded) {
isGrounded = false;
anim.SetBool("Grounded", isGrounded);
rb.transform.position += Vector3.up * jumpForce;
}
if (Input.GetButtonUp ("Jump") && isGrounded == false)
{
isGrounded = true;
anim.SetBool ("Grounded", isGrounded);
}
// Recherche de toutes les collisions possibles en cours de mouvement
Collider2D[] hits = Physics2D.OverlapBoxAll(transform.position, boxCollider.size, 0);
foreach (Collider2D hit in hits)
{
// Ignorer le propre collider du personnage.
if (hit == boxCollider)
continue;
84
ColliderDistance2D colliderDistance = hit.Distance(boxCollider);
// Test de rencontre "overlapping"
if (colliderDistance.isOverlapped)
{
transform.Translate(colliderDistance.pointA - colliderDistance.pointB);
// Si un objet se trouve à proximité, arrêt de déplacement ou de saut.
if (Vector2.Angle(colliderDistance.normal, Vector2.up) < 90 && rb.velocity.
y < 0)
{
isGrounded = true;
anim.SetBool ("Grounded", isGrounded);
}
}
}
}
}
Ensuite, le mouvement est géré, en fonction des touches de clavier utilisées, par les fonctions RigidBody. Translate,
pour le déplacement latéral et RigidBody.position pour le saut. Nous les connaisons, déjà, car nous les avons
étudiées et utilisées lors de l’exercice précédent.
Simultanément, l’animation est déclanchée par la modification des paramètres de l’animateur (Speed et Grounded).
Le code est simple et fluide mais les fonctions utilisées désactivent la gestion des collisions qui est traitée,
séparément :
On recherche tous les objets dotés d’un BoxCollider et on teste leur distance par rapport au personnage (Player) ;
s’ils se rapprochent, on immobilise le personnage devant l’obstacle qu’ils constituent.
85
VI – Création de personnages 3D et leur intégration dans Unity :
1) Création de personnages 3D :
Unity n’est pas approprié pour créer des personnages 3D, bien que ce soit, théoriquement possible ; mais,
l’intégration de personnage créé avec des outils externes est prévue et facilitée par les dispositions que nous
allons examiner.
Les grands éditeurs de logiciels de dessin en 3D (tels que 3DSMax ou Maya d’Autodesk, Blender …) disposent
des moyens nécessaires pour le faire mais ils s’adressent, surtout, à des professionnels car ils demandent
une formation préalable dissuasive.
Nous allons citer ceux qui semblent mieux adaptés pour des non-initiés et et, nous ne retiendrons, pour ce
tutoriel, que MIXAMO, l’outil interactif, dérivé de Fuse et mis en ligne par Adobe car il est très simple à
utiliser et suffisant pour ce tutoriel.
a) Les 3 outils externes les plus recommandés pour créer des personnage 3D :
- Fuse d’Adobe (version pour étudiants) :https://www.youtube.com/watch?v=BEHU0Pv73rY
- Character Generator de AutoDesk (version pour étudiants),
- MakeHuman (OpenSource).
Ils offrent des possibilités impressionnantes, malgré leur simplicité d’emploi et disposent de
bibliothèques suffisantes pour permettre de satisfaire les besoins d’un amateur.
Ils sont présentés, dans une courte vidéo, en français, que vous pouvez consulter, à l’adresse
suivante :https://www.youtube.com/watch?v=v65ZzKZXMDw&vl=en; en annexe, vous trouverez
les liens utiles, pour se les procurer, par téléchargement.
b) Utilisation de Mixamo (version en ligne dérivée de Fuse) :
Il suffit d’aller sur le site Mixamo.com et de s’y inscrire, gratuitement, pour pouvoir l’utiliser.
Nous allons reprendre les bases qui sont exposées, dans une vidéo, à l’adresse suivante :
https://www.youtube.com/watch?v=QkdyNRIRql8
Elles vont nous apprendre comment :
- Choisir un personnage « Character » :
- Choisir une animation « Animation » :
- Exporter vers un fichier fbx pour Unity :
- Intégrer le fichier dans Unity.
86
- Choisir un personnage :
Dès que vous êtes identifié, vous parvenez à la page suivante (en 2 parties) :
A gaucheèMenu CharacterèVous permet de tester et ce choisir parmi un nombre
impressionnant de personnages (48 par pages X par 52 pages !!!)
Une fois l’onglet Character sélectionné, Rechercher « Ybots » :
A droite : Vous pouvez visualizer le personnage dans une fenêtre d’animation :
87
Il est, pour l’instant, immobile dans une position dénommée « T-Pose ».
- Choisir une animation :
Changer, maintenant d’onglet, pour passer en « Animation » ; supprimer le filtre de recherche
antérieur, pour saisir « Basic Locomotion » :
Chaque vignette est déjà animée, en réduction, et le nombre, en bas à gauche, indique le
« Locomotion Pack » et observer que sur la droite, le personnage « Y Bots » s’est mis en
mouvement :
88
Mais, sauf, à le mettre , immédiatement, en pause, il disparait vers la gauche pour ne revenir
que lorsque le cycle est terminé.
Sélectionner la camera, au bas du menu, à gauche : « Toggle Follow Camera ». Qui permet à
l’animation de faire du « sur place », donc d’être visualisable, en permanence, au long des 12
clips qui la composent.
- Exporter le personnage et son animation :
Clic sur Download ouvre la fenêtre DownLoad Settings
Modifier le format en : « FBX for Unity( .fbx), et laisser les 3 autres options proposées par défaut,
Clic sur « Download », en bas à droite :
Attendez la fin , puis allez voir dans votre Répertoire de téléchargement (classé par date
décroissantes) :
En haut, vous trouvez le fichier
Double clic pour voir le contenu :
89
Vous y trouvez, le fichier du personnage ybot.fbx, ainsi que les 12 fichiers fbx de l’animation.
Déposer les dans le sous-répertoire « Character\ybot » que vous aller créer dans celui de la
Scène du _TutoNo6 : Outils et Tutoriels\Assets\_TutoNo6\Character\ybot.
c) Intégration du personnage dans Unity :
Dans Unity, créer une nouvelle scène intitulée « Setup_ybot » puis observer le contenu des
Assets du répertoire ybot :
La copie des fichiers exportés de Mixamo a créé, dans Unity, un prefab pour chaque animation
et, un dernier concernant le personnage, lui-même « ybot ».
90
Sélectionner ce dernier et observer ses propriétés, dans l’inspecteur :
Il est composé de 4 onglets qui représentent les éléments importés : Model = Le personnage,
Rig : La structure osseuse de son corps, Animation : Son animation, Materials : Les matériaux et
textures de sa peau et de ses vêtements.
Il faut finir de paramétrer ces composants avant de pouvoir les utiliser :
Dans l’onglet Rig, choisir le type d’animation « Humanois » :
Puis Clicker sur e bouton « Apply » qui permet (si ce n’était déjà fait) de créer l’Avatar du
personnage, c’est-à-dire l’enveloppe physique de son corps (Os, chair, peau, cheveux yeux,
vêtements) ; en déroulant, dans les Assets, ybot, le fichier Avatar se trouve en bas :
Un bouton de configuration est apparu, dans l’onglet Rig
Un clic va nous permettre de comprendre la structure de l’avatar :
91
L’onglet Mapping permet de voir un schéma du corps et des os principaux (représentés par des
cercles) sur lesquels va s’articuler l’animation. La fenêtre Scene, à gauche, permet de visualiser le
rendu qui en résulte.
L’onglet « Muscles & Settings » figure cette articulation mais nous ne l’examinerons pas.
Dérouler l’onglet Pose, se trouvant sous le schema, pour choisir l’option « Enforce T-Pose » :
Clic sur le bouton « Apply » qui s’est activé après notre choix.
Puis Clic sur « Done » pour retourner dans la fenêtre générale du paramétrage.
Aller dans l’onglet « Materials » pour régénérer les fichiers de Marières et Textures (sinon notre personnage
apparaitra blanc dans la scene !!!)
92
Conserver les paramètres par défaut et clicker sur « Extract Textures » (s’il est actif, sinon Materials) , il vous
est demandé de choisir un répertoireèCréer un dossier Textures ou Materials
(\Assets\_TutoNo7\Character\ybot\Textures ou Materials) et Sélectionner le…
L’opération s’effectue et, à la fin, si vous avez utilisé Textures, un message d’anomalies peut s’afficher :
Clic sur « Fix now » et les Materials seront créés en même temps que les Textures.
Après l’opération, vous pouvez constater le résultat dans l’arborescence des Assets :
Elle est très simple, dans ce cas, puisqu’il s’agit d’un robot.
Pour ne pas rallonger, inutilement, l’exercice, je vous renvoie, pour plus de détails aux nombreuses vidéos
qui montrent les possibilités offertes pour le perfectionner.
NOUS AVONS TERMINE L’IMPORTATION DU PERSONNAGE DANS UNITY !!!
L’OPERATION PEUT SEMBLER FASTIDIEUSE OU ETRANGE MAIS DEMANDE PEU D’EFFORTS COMPARE AU
RESULTAT OBTENU !!! PAR CONTRE SI VOUS OUBLIEZ UNE ETAPE (Comme d’autres l’ont fait, y-compris
moi), CELA NE FONCTIONNERA PAS ET IL FAUDRA RECOMMENCER.
J’ai détaillé l’importation de YBOT, pour l’exemple mais, j’ai terminé ce travail pour les personnages suivants
qui sont fournis dans les fichiers de support :
- ACINA (by_J._Laygo) : Sorte d’amazone armée d’un arc
- ARISSA : Pirate Punk
- MARIA (J-J-Ong) : Guerrière médiévale blonde
Et, surtout BETA : Un autre robot de genre féminin qui va nous servir dans les exercices
Pour les voir :
Dans le répertoireè_TutoNo7\Scenes, créer une scène nommée « Test_Characters » et y déposer ces
prefabs 2 par 2 pour ne pas encombrer l’écran :
93
Ils sont immobiles les braus en croix (T-Pose), il reste à les animer.
94
VII – Exemples d’utilisation des controleurs et scripts d’animation :
En observant, les propriétés d’un des personnages, dans la scène précédente, vous constatez qu’il est doté
d’un composant d’animation (« Animator ») :
L’avatar est renseigné mais il faut le doter d’un « controller ».
Nous avons, déjà, rencontré le composant « Controller » pour l’animation d’un sprite 2D, mais nous allons
approfondir et étendre son utilisation dans le cas d’un personnage en 3D.
1) Principe du système d’animation intégré à Unity (Mecanim):
Précédemment, nous avions inséré des clips d’animation, qui constituent des étapes ou états (« State ») ; elles
sont reliés par des transitions auxquelles on a associé des paramètres. C’est le changement de la valeur d’un ou
de plusieurs paramètres qui déclanche l’animation.
C’est pourquoi, le système, dans son ensemble est, parfois, qualifié de machine à états.
95
Mais, ces schémas d’animation devenant, rapidement complexes, illisibles et difficiles à réutiliser, Unity a prévu
la possibilité de créer des :
- Sous-états : qui permettent de poursuivre le schéma dans une autre fenêtre (et ainsi de suite)…
- Enchainements de clips, en séquense (BlendTree).
Eux-même, reliés entre eux par des transitions conditionnelles.
Les possibilités sont nombreuses et il est necessaire de les expérimenter, progressivement, pour s’y adapter.
1) Exemples de Controller d’animation :
a) Le plus simple (composé d’un seul clip)
Sélectionner, dans, les Assets, le répertoire Animations , puis par un clic droitèCreateè
AnimatorController :
Nommer le fichier : Beta_walking
Chercher ce clip dans le répertoire « Common_Workspace :
Déposer cette animation dans le « Base Layer » de l’animator :
96
b) Controller simple (plusieurs clips acessibles par script) :
Comme pour exécuter un saut, manier une arme, faire tomber ou mourir un personnage :
Nommer le fichier : Multi_Actions
Comme précédemment, nous allons y déposer quelques clips provenant des Animations
complémentaires du robot BETA :
Standing_2H_Cast_Spell_01 Standing_2H_Magic_Attack_01
standing_melee_attack_kick_ver_2 standing_melee_run_jump_attack
sword_idle death2
Adopter la disposition et établir les transitions comme sur le schéma, ci-dessous (Nous avons déjà vu
cela, au chapitre, se reporter à lui, en cas de besoin) :
NOTE : J’ai renommé les transitions avec des mots plus courts
Pour pouvoir paramétrer les transition, nous devons créer un paramètre de type nombre entier « Int » et
dénommé « AnimNbr » :
97
Les transitions auront les conditions suivantes :
Thinking Magic_Spell AnimNbr Equals 1
Thinking Magic_Attack AnimNbr Equals 2
Thinking Kick_Ground AnimNbr Equals 3
Thinking Kick_Jump AnimNbr Equals 4
Thinking Sword_Idle AnimNbr Equals 5
Thinking Death2 AnimNbr Equals 6
Tous les 6 Thinking AnimNbr Equals 0
Avant de poursuivre, avec un cas plus complexe, testons ces animateurs simples dans une scene :
Le premier ne nécessite même pas de script…
c) Créer une scene intitulée RootMotion :
Puis y insérer le Prefab Terrain que nous avons, déjà, utilisé dans le TutoNo5 et le personnage Beta
dont le prefab se trouve dans \Common_Workspace\3D_Character_Fbx\Beta, tout en bas.
Faire glisser le Controlleur « Beta_Walking » dans l’animator Controller.
Vérifier le positionnement de la Camera et du personnage, puis tester l’éxécution : L’animation se
joue mais le personnage quitte la scene en marchant …
Revenir dans l’inspecteur de propriété de Beta et décocher la case « RootMotion », puis rejouer la
scene : Cette foisl’animation s’exécute, en continu mais le personnage marche ; en faisant du « sur
place » :
98
d) Créer une nouvelle scene intitulée MultiActions :
Par copie de la scene prédédente car elle contient les mêmes objets, changer, selement, le controller
de l’animator pour celui qui porte le même nom que la scene.
Y insérer un UI Panel (avec un composant UI Toggle Group) qui sera composé d’un texte
d’information et de 7 cases à cocher (UI Toggle) qui serviront à déclancher les animations, et à les
stopper :
Dans Info saisir : « Cocher l'action à exécuter, arrêter, puis recommencer ... »
Ne pas oublier de rattacher chaque Toggle au Toggle Group du Panel.
Créer le script suivant :
using UnityEngine;
using UnityEngine.UI;
public class AnimActions : MonoBehaviour
{
public Toggle[] Choix;
private Animator anim;
private Vector3 startPos;
private Vector3 recul;
void Start()
{
anim = GetComponent<Animator>();
startPos = transform.position;
recul = new Vector3 (startPos.x, startPos.y, startPos.z + 3);
}
public void ToggleClic()
{
int cpt = 0;
foreach (Toggle thisOption in Choix)
{
if (thisOption.isOn)
{
if (cpt != 4) {transform.position = startPos;}
else {transform.position = recul;}
anim.SetInteger("AnimNbr",cpt);
break;
} 99
cpt++;
}
}
}
Il est court et simple à comprendre : Chaque bouton va transmettre au controleur d’animation, le
numéro de l’action à exécuter.
On récupère tous les composants Toggle dans une liste. Le parametre « AnimNbr » aura le numero
de classement de chaque case à cocher (de 0 à 6).
L’action No 4 Kick_Jump fait avancer le personnage, il faut donc le faire reculer avant de sauter pour
ne pas sortir de l’écran.
Il reste, donc, à relier la fonction ToggleClic à l’évènement « OnValueChange » de chacun d’eux :
Il ne reste plus qu’à exécuter la scene pour la tester.
2) Controller mixant BlendTree et simple clip :
Ce dernier controleur va nous reservir pendant tous les autres exercices de ce tutoriel ; car son utilisation
peut être généralisée à tous les personnages de type « Humanoid ».
Créer un nouveau Controller intitulé « AdvPlayer_Mixamo », il va nous permettre d’alterner la marche, la
course et le saut, en fonction des besoins .
Commençons par créer les paraètres suivant ( 2 nombres décimaux et 3 booléens) :
Dans l’éditeur de Layer, un Clic droit permet de créer un BlendTree :
100
Un Sous-état particulier a été créé nommé BlendTree comme le composant qu’il contien ; il est conditionné,
composant, l’inspecteur de propriétés montre qu’il est possible de lui ajouter des clips d’animation
(Motion) :
Changeons le nom en « Movement_walking » puisque nous voulons le destiner à la marche.
Pour cela il faut changer le « Blend Type » en « 2D Simple Directionnal » :
Indiquons que le second axe correspondra à la variable YBlend :
Le BlendTree se présente, maintenant, ainsi
clip de marche qui servira à aller en Avant, en Arrière, à Droite ou à Gauche.
Puis, Tirer / Déposer les clips d’animation du robot Beta, dans chaque emplacement :
Un schéma représentant les positions d’un « Joystick » permet, d’éventuellement, modifier les valeurs
par : -1, 0 ou 1. Dans notre cas, les positions, par défaut, sont correctes.
De retour dans le Layer principal, il faut recommencer l’opération pour créer et paramétrer un autre
BlendTree pour la course « Movement_running :
101
Il faut, enfin, ajouter, dans le Layer principal, le clip de saut « Jumping, puis à créer et paramétrer les
Transitions pour aboutir au schéma suivant :
Movement_walking Movement_running Running Equals True
Movement_running Movement_walking Running Equals False
Movement_walking Jumping Jump Equals True
Jumping Movement_walking Jump Equals False
3) Créer une nouvelle scene intitulée Character_3DAnimation :
Je me suis inspiré du travail mis à disposition, sur le site github, à l’adresse suivante :
https://github.com/valgoun/CharacterControllerpour le décor et pour le script que j’ai adaptés pour cet
exercice.
102
a) L’animation sans mouvement de caméra :
- Dans la scene, ajouter le preffab de décor (fourni) intitulé « Mosaic _tiles »
- Ajouter le prefab du personnage Beta que nous allons déconstruire (uniquement dans la scene)
pour pouvoir le modifier :
- Renommer le pour la circonstance en Player_Cc (Cc pour indiquer qu’il utilise un
CharacterController et pas un RigidBody).
- Remplacer le controleur d’animation par le dernier créé « AdvPlayer_Mixamo ».
- Ajuster le positionnement des objets et la camera pour obtenir le visuel suivant :
ATTENTION : IL FAUT AJUSTER LES PARAMETRES DU CHARACTER CONTROLLER POUR OBTENIR UN
RESULTAT SATISFAISANT - VOICI CEUX QUE J’AI UTILISES :
Je vous renvoie au manuel Unity pour les détails :https://docs.unity3d.com/Manual/class-
CharacterController.html. Noter, simplement, que «Step Offset » est, précisément, adapté pour
permettre de gravir un escalier suivant la hauteur des marches.
103
- Créer et rédiger le script suivant :
using UnityEngine;
public class Character_3DAnim : MonoBehaviour
{
public GameObject _thePlayer; // Ajout
public float Speed = 2f;
public float JumpHeight = 3f;
public float Gravity = -100f;
public float GroundDistance = 0f;
public LayerMask Ground;
private CharacterController _controller;
private Vector3 _velocity;
private bool _isGrounded = true;
private Animator anim; // Ajout
void Start()
{
_thePlayer = GameObject.Find(_thePlayer.name);
_controller = _thePlayer.GetComponent<CharacterController>();
// Ajout
anim = _thePlayer.GetComponentInChildren<Animator>();
}
void Update()
{
if (_isGrounded && _velocity.y < 0)
_velocity.y = 0f;
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Ve
rtical"));
_controller.Move(move * Time.deltaTime * Speed);
if (move != Vector3.zero)
transform.forward = move;
104
if (Input.GetButtonDown("Jump"))
{
_isGrounded = false;
anim.SetBool("Jump", true);
_velocity.y += Mathf.Sqrt(JumpHeight * -Gravity/2);
}
else
{
_isGrounded = true;
anim.SetBool("Jump", false);
}
_velocity.y += Gravity * Time.deltaTime;
_controller.Move(_velocity * Time.deltaTime);
// Animator Parameters
anim.SetFloat("BlendX", (Input.GetAxis("Horizontal") * 2));
anim.SetFloat("BlendY", (Input.GetAxis("Vertical") * 2));
anim.SetBool("Walking", (anim.GetFloat("BlendX") != 0 || anim.GetFloat("Blend
Y") != 0));
}
}
Vous êtes déjà familiarisés avec les fonctions utilisées dans ce script (je les livre sans commentaires).
Noter l’utilisation successive de :
_thePlayer = GameObject.Find(_thePlayer.name);
_controller = _thePlayer.GetComponent<CharacterController>();
anim = _thePlayer.GetComponentInChildren<Animator>();
Pour initializer un objet, puis un de ses composants de 1er niveau et, ensuite, un sous-composant.
Ce sera très utile en toutes circonstances.
- Ajouter ce script aux composants du Player_Cc :
NE PAS OUBLIER DE LIER LA VARIABLE _thePlayer AU Player_Cc ET DE CHOISIR LE LAYER Ground
UTILISE POUR REPERER LES OBJETS SUR LESQUELS LE PERSONNAGE EST AUTORISE A SE
MOUVOIR. SANS CES INFORMATIONS, VOUS OBTIENDREZ DES MESSAGES D’ERREURS.
- Tester l’exécution de la scene, cela doit fonctionner si vous avez bien suivi le tutoriel sinon il faut
le reprendre plus minitieusement.
Pour que le résultat soit plus concluant, il va falloir intégrer une camera permettant de suivre le
personnage dans ses mouvements.
105
b) L’animation avec mouvement de caméra :
- Renommer la Camera par défaut, en Camera_Cc pour la reconnaitre après modification.
- Créer un nouveau Script intitulé « ZoomAndFollow_Camera :
using UnityEngine;
public class ZoomAndFollow_Camera : MonoBehaviour {
public GameObject target;
public float damping = 3;
Vector3 offset;
void Start() {
offset = transform.position - target.transform.position;
}
void LateUpdate() {
Vector3 desiredPosition = target.transform.position + offset;
Vector3 position = Vector3.Lerp(transform.position, desiredPosition, Time.del
taTime * damping);
transform.position = position;
transform.LookAt(target.transform.position);
}
}
Il permet à la camera de suivre le personnage, en conservant la distance, entre eux, prévue au départ (offset)
la variable Damping servant d’amortisseur à la vitesse de suivi (caractéristique de l’interpolation linéaire).
2 préalables sont nécessaires
- Ajouter un GameObject vide au Player_Cc, le dénommer Target ; pour le rendre visible, dans
l’éditeur de scene, le tagger d’un point rouge
et positionner le devant le personnage à hauteur de tête :
106
- Ajouter le script aux propriétés de la Camera_Cc et lier ses variables :
Tester le fonctionnement et vérifier si le résultat correspond à nos attentes.
4) Utilisation d’une Camera de type « Orbitale » capable, à la fois, de suivre le
personnage et d’examiner l’environnement avant de le déplacer :
a) Sources des objets réutilisés :
- Décor de désert mis gacieusement à disposition par RuneMark Studio sur l’AssetStore de Unity
https://assetstore.unity.com/packages/3d/environments/landscapes/polydesert-107196
- Orbital camera pour personnage 3D trouvé sur le site github :
https://github.com/jm991/UnityThirdPersonTutorial
b) Créer une nouvelle scene, dénommée Character_Orbit_Cam :
- Placer la camera par défaut (Main Camera) en position (transform) en X = 31, Y = 3 et Z = 18
- Insérer le prefab du décor : Desert_Arena (dans sa position par défaut, en X = Y = Z = 0).
- Insérer le prefab du personnage précédent : Player_cc : Désassembler le prefab (clic droit sur le
prefab, dans la sceneèUnpack Prefab Completely) , pour supprimer l’objet enfant « Target »
dont nous n’aurons plus besoin (cela ne le supprime pas du Prefab lui-même).
Le placer en position (transform) X = 29, Y = 2 et Z = 21
Vérifier que ses propriétés aient bien été conservées comme ci-dessous : :
107
La présentation dans la fenêtre Game, en mode éditeur doit être la suivante :
- Tester la scene pour vérifier qu’elle fonctionne, avant de changer de camera : Le robot Beta se
déplace dans les 4 directions mais sans rotation et dans un décor et une camera fixes
108
c) Modifier la scene de la façon suivante :
- Créer un nouveau script pour le personnage, dérivé de Character_3DAnim, et nommé
« Multi_Player_Controller ».
J’ai commenté et marqué en vert les ajouts :
using UnityEngine;
public class Multi_Player_Controller : MonoBehaviour
{
public float walkSpeed = 5.0f;
public float runSpeed = 8.0f;
public float jumpSpeed = 6.0f;
public float gravity = 10.0f;
private Vector3 moveDirection;
private bool grounded;
private float speed;
private CharacterController controller;
private Transform myTransform;
private Animator anim;
private Quaternion newRotation; // Ajout
private float h,v; // Ajout
[HideInInspector] public bool walking;
public Transform pivotTransform; // Ajout pour Direction et Rotation
// Use this for initialization
void Start()
{
controller = GetComponent<CharacterController>();
anim = GetComponent<Animator>();
moveDirection = Vector3.zero;
grounded = false;
myTransform = transform;
speed = walkSpeed;
}
109
private void FixedUpdate()
{
float inputX = Input.GetAxis("Horizontal");
float inputY = Input.GetAxis("Vertical");
h = inputX; // Ajout pour Direction et Rotation
v = inputY; // Ajout pour Direction et Rotation
float inputModifyFactor = (inputX != 0.0f && inputY != 0.0f) ? 0.6701f : 1.0f
;
anim.SetFloat("BlendX", (inputX * 2));
anim.SetFloat("BlendY", (inputY * 2));
anim.SetBool("Walking", (anim.GetFloat("BlendX") != 0 || anim.GetFloat("Blend
Y") != 0));
}
void Update()
{
if (grounded)
{
if (Input.GetButtonDown("Run"))
speed = (speed == walkSpeed ? runSpeed : walkSpeed);
walking = h != 0f || v != 0f;
CalcMovement (h, v); //Ajout pour recherche direction
HandleRotation (); //Ajout pour rotation
if (Input.GetKeyDown(KeyCode.Space))
{
anim.SetBool("Jump", true);
moveDirection.y = jumpSpeed;
}
else {anim.SetBool("Jump", false);}
bool running = Input.GetButton("Run");
speed = running ? runSpeed : walkSpeed;
anim.SetBool("Running", running);
}
grounded = (controller.Move(moveDirection * Time.deltaTime) & CollisionFlags.
Below) != 0;
moveDirection.y -= gravity * Time.deltaTime;
}
110
//Début Ajout
void CalcMovement (float h, float v)
{
moveDirection = new Vector3 ();
if (v != 0 || h != 0)
moveDirection = v * pivotForward() + h * pivotRight();
moveDirection = moveDirection.normalized * speed;
}
void HandleRotation()
{
if (walking)
newRotation = Quaternion.LookRotation (moveDirection, Vector3.up);
transform.rotation = newRotation;
}
Vector3 pivotForward()
{
Vector3 forwardVector = pivotTransform.transform.forward;
forwardVector.y = 0;
return forwardVector;
}
Vector3 pivotRight()
{
Vector3 rightVector = pivotTransform.transform.right;
rightVector.y = 0;
return rightVector;
}
// Fin Ajout
}
Ces ajouts ont 2 buts précis :
- Créer une variable Pivot qui va permettre au personnage de tourner avec la Caméra
- Gérer, simultanément, la rotation et le mouvement.
- Supprimer Main Camera pour la remplacer par le prefab : Camera Rig (fourni)
La placer dans la même position (en X = 31, Y = 3 et Z = 18)
111
Cette Camera contient 2 enfants en cascade hiérarchique :
vérifier les scripts qui devraient se trouver en propriétés, il s’agir de :
o CameraControl.cs et
o CameraOcclusionProtector.cs (optimise les calculs du processeur)
Je les aient fourni parmi les fichiers de l’exercice (pour les remplacer éventuellement).
Tirer / Déposer le personnage Player_Cc dans le champ Target du script CameraControl
- Remplacer, dans Player_Cc, le script antérieur (Character_3DAnim) par le nouveau :
Tirer / Déposer le Pivot de la Camera dans la variable du Multi_Player_Controller
112
- Tester la scene à nouveau pour VERIFIER QUE LE RESULTAT RECHERCHE EST ATTEINT.
LE RESULTAT POSSEDE UNE QUALITE PROCHE DES MEILLEURS JEUX VIDEOS REALISES PAR
DES PROFESSIONNELS
- Vous pourrez examiner vous-même, le script CameraControl qui gère, comme son nom
l’indique, le mouvement de la Camera, il est, suffisamment, commenté par son auteur et je
ne ferais pas mieux…
c’est trop tecnique pour notre niveau.
Ce mode de visualisationb et de déplacement est dénommé « Third Person Controller » car tout tourne
autour du personnage ; à l’opposé, un mode « First Person controller » rendrait le personnage invisble pour
donner la sensation que le joueur derrière son écran est, lui-même, le personnage (très utilisé dans les jeux
de guerre ou de combat de type FPS comme First Person Shooter).
C’est ce que nous allons entreprendre, dans une scene unique, permettant d’expérimenter ces 2 modes.
Mais, dans le tutoriel suivant car celui-ci est déjà suffisamment chargé…
D’ailleurs, pour le dernier Tutoriel No 8 qui suit :
J’ai décidé de fournir les objets et scripts nécessaires, pour vous simplifier la
tache, en pensant que, si vous avez suivi, avec application, les tutoriels
précédents, vous êtes capable de les comprendre, sans nécessairement,
avoir de besoin de les construire.
Voici le contenu du répertoire du _TutoNo8, dans les Assets du projet :
113
VIII – Exemples de réutilisation d’une même scène avec des personnages
différents :
1) Basculer, dans une même scène, d’un mode ThirdPerson vers un mode
FirstPerson et inversement :
a) Dupliquer la scene precédente (Ctrl + D) et la renommer « FirstThird_Controller »,
- Dans l’arborescence de Camera_Rig, renommer la Camera en « FPerson_Camera » :
b) Réutilisation de prefabs préparés à l’avance :
- Ajouter le prefab, fourni, dénommé « ThirdFirstOptions » :
Il s’agit d’un UI Canvas contenant 2 boutons qui permettront de basculer, alternativement d’un
mode à l’autre, d’où leurs noms « Third » et « First », en agrégé (nous reprendrons leur paramétrage
quand les autres objets et scripts auront été créés :
- Ajouter le prefab, fourni, dénommé « FPerson_invisible » :
Il s’agit d’un GameObject destiné à recevoir du code et une camera qui a été dénommé
« FPerson_Camera », pour répondre à celle contenue dans Camera_Rig. Comme il est préférable de
n’avoir qu’une seule camera active dans la même scene, désactiver, momentanément, l’ensemble du
prefab (en décochant la case qui précède son nom) :
Constater qu’il est doté d’un « Capsule collider », pour réagir aux obstacles :
Respecter les valeurs Height, radius et Center
114
c) Examen des scripts incorporés :
- Un script, dénommé, « Invisible_Moves » est attaché à ce dernier préfab. Il est utilisé pour déplacer la
capsule invisible dans les 4 directions ; comme vous le voyez, ci-dessous, il est très concis :
using UnityEngine;
public class Invisible_Moves : MonoBehaviour
{
public float speed = 10f;
private float UpAndDown;
private float RightAndLeft;
// Use this for initialization
void Start () {
// turn off the cursor
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update () {
//Input.GetAxis() is defined by user's input in
//==> Edit, Project Settings, Input
UpAndDown = Input.GetAxis("Vertical") * speed * Time.deltaTime;
RightAndLeft = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
transform.Translate(RightAndLeft, 0, UpAndDown);
if (Input.GetKeyDown("escape")) {
// turn on the cursor
Cursor.lockState = CursorLockMode.None;
}
}
}
anim = GetComponent<Animator>();
La gestion de « FFirst_Camera » sera assurée par un script qui lui sera attaché ( « MouseCamLook » ) ; ilmoveDirection = Vector3.zero;
permettra à la Camera de suivre les mouvements de la souris (comme vous le verrez, ci-dessous, j’ai réutiliségrounded = false;
et adapté un modèle trouvé sur github et référencé dans l’en-tête du scriptmyTransform = transform; ) :
speed = walkSpeed;
}
115
/*
* Inspired from : github.com/jiankaiwang/FirstPersonController
* Added limitations to camera rotation up and down
*/
using UnityEngine;
public class MouseCamLook : MonoBehaviour {
public float sensitivity = 5.0f;
public float smoothing = 2.0f;
public float minCamAngle = -45f;
public float maxCamAngle = 45f;
public GameObject _player;
private Vector2 mouseLook; // mouse moves on 2D screen
private Vector2 smoothV;
// Use this for initialization
void Start () {
_player = this.transform.parent.gameObject;
}
void Update () {
// newDir resulting from User's Input and sensitivity
var newDir = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse
Y"));
newDir = Vector2.Scale(newDir, new Vector2(sensitivity * smoothing, sensitivi
ty * smoothing));
// Smooth camera movement by Linear interpolation
smoothV.x = Mathf.Lerp(smoothV.x, newDir.x, 1f / smoothing);
smoothV.y = Mathf.Lerp(smoothV.y, newDir.y, 1f / smoothing);
// Change camera's position with UpAndDown limitation
// Vector3.right means RightOrLeft / Vector3.up means UpOrDown
mouseLook += smoothV;
mouseLook.y = Mathf.Clamp(mouseLook.y, minCamAngle, maxCamAngle);
transform.localRotation = Quaternion.AngleAxis(-mouseLook.y, Vector3.right);
// Player must follow the Camera
_player.transform.localRotation = Quaternion.AngleAxis(mouseLook.x, _player.t
ransform.up);
}
}
L’objectif sera d’utiliser 2 boutons (intitulés « First » et « Third ») pour activer, alternativement, soit la
capsule invisible et sa FPerson_Camera, soit l’objet « Player_Cc » et sa TPerson_Camera.
116
d) Comment utiliser les 2 modes dans la même scene :
Pour y parvenir, il nous faudra utiliser un nouveau script rattaché à Player_Cc (il est fourni dans le prefab) et
2 boutons (également inclus dans un prefab que nous allons utiliser).
- Ouvrir le script dénommé « SwitchCamera » pour l’examiner (il se trouve dans les propriété de
Player_Cc) :
using UnityEngine;
public class SwitchCamera : MonoBehaviour {
public bool isFirstPerson;
public GameObject camera_Rig;
public GameObject default_Player;
public GameObject fPerson_Player;
// Use this for initialization
void Start () {
isFirstPerson = false;
camera_Rig.SetActive(!isFirstPerson);
fPerson_Player.SetActive(isFirstPerson);
default_Player = GameObject.Find(default_Player.name);
default_Player.SetActive(!isFirstPerson);
}
public void SwitchCam(bool isFirst)
{
if ((isFirst) && (default_Player.activeSelf))
{
isFirstPerson = true;
default_Player.SetActive(false);
fPerson_Player.SetActive(true);
camera_Rig.SetActive(false);
}
if ((!isFirst) && (!default_Player.activeSelf))
{
isFirstPerson = false;
default_Player.SetActive(true);
camera_Rig.SetActive(true);
fPerson_Player.SetActive(false);
}
}
}
Il devrait permettre le fonctionnement attendu …
117
- Insérer, maintenant, le prefab intitulé « FirstThirdOptions », un UI Canvas contenant les 2 boutons :
Chaque bouton possède un évènement (Event) « OnClic » qui le relie à la fonction « SwitchCam » du
script « SwitchCamera », via son propriétaire Player_Cc :
AVANT DE TESTER, VERIFIER QUE LES OBJETS SONT BIEN RELIES ENTRE EUX :
o FPerson_Camera à Player_Cc, via le script MouseCamLook :
o TPerson_Camera à Player_Cc, via le script CameraControl :
o Player_Cc au Pivot contenu dans Camera_Rig via le script Multi_Player_Control :
118
o Enfin, le script SwichCamera contenu dans Player_Cc doit être relié à :
Au prix de ces vérifications indispensables, vous pouvez jouer la scene qui offre un résultat à la
hauteur de nos efforts !!!
Vous percevez mieux comment les opérations se connectent entre elles pour assurer la meilleure
réutilisation possible des différents objets, Animations et autres Scripts.
Il reste un dernier exercice essentiel et, encore plus spectaculaire à accomplir. Il répondra à une question
qui, certainement, vous brûle les lèvres :Peut-on changer de personnage, dans la
même scene, en réutilisant tous les autres composants ?
Pour que ce soit réalisable, il faut que tous les personnage soient detype « HUMANOID »et que leurs
avatars partagent la même structure osseusede base. C’est, heureusement le cas des
personnages, importés de Mixamo, que j’ai choisi…
119
2) « Retargeting » ou changement de personnage avec mêmes Controllers et Scripts :
a) Créer une scene intitulée « Retarget_4Avatars »
Supprimer la caméra par défaud, puis ajouter les prefabs fournis, dans cet ordre :
- Desert_Arena qui se trouve en : \Assets\_TutoNo7\Prefabs\Environment
- Canvas_MultiChar qui se trouve en : \Assets\_TutoNo8\Prefabs\UI
- Multi_Camera_Rig qui se trouve en : \Assets\_TutoNo8\Prefabs\Camera
- 4 Personnages qui se trouvent en : \Assets\_TutoNo8\Prefabs\Characters
o Beta
o Maria,
o Acina
o Arissa
Pour éviter les soucis de positionnement, je vous indique les coordonnées de chacun (Propriétésè
Transform) : X Y Z
Desert Arena 0 0 0
Multi_Camera_Rig 31 2 17
Les 4 personnages 32 0.1 23
Ces personnages sont, exactement, à la même place ; pour éviter les chevauchement, ne laisser Actif
que Beta et décocher cette propiété pour les 3 autres.
Vous obtenez, dans la fenêtre Game, en mode édition, le résultat suivant :
120
b) Le Canvas contient un Titre et un TogglePanel regoupant 4 cases à cocher (une pour chaque
personnage) :
Le titre affichera ceci, à l’exécution :
Et les boutons cela :
Pour basculer vers un autre personnage, il suffira de cocher une case vide ou d’utiliser les touches
numériques du clavier indiquées.
Après avoir examiné les autres objets, nous verrons comment ils sont connectés.
c) L’objet Multi_Camera_Rig :
Il est dérivé du prédédent « Camera_Rig » mais le script attaché à la Camera va afficher les propriétés
suivantes :
En déposant les objets comme indiqué, on fera le lien entre une case à cocher et un personnage.
121
- Examinons le script « Multi_Char_CamControl » :
Comme il est dérivé « CameraControl » que nous connaissons déjà, je ne montre que les ajouts qui
ont été apportés :
using UnityEngine;
using UnityEngine.UI;
public class MultiChar_CamControl : MonoBehaviour
{
public Toggle[] CharSelection;
public GameObject[] CharToSelect;
private int selectNo;
Lignes sautées … … … … … … … …
protected virtual void Start()
{
// Ajout pour changer de personnage
if (CharSelection.Length != CharToSelect.Length)
{
Debug.Log("Le nombre de boutons à cocher doit être identique au nombre de
personnages, Corrigez puis relancez...");
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
else
{
int ScanNo = 0;
foreach (Toggle thisOption in CharSelection)
{
if (ScanNo == 0)
{
CharSelection[0].isOn = true;
CharToSelect[0].SetActive(true);
target = CharToSelect[0].transform;
} else
{
CharSelection[ScanNo].isOn = false;
CharToSelect[ScanNo].SetActive(false);
}
ScanNo++;
}
}
}
Lignes sautées … … … … … … … …
122
protected virtual void Update()
{
var controlRotation = PlayerInput.GetMouseRotationInput();
this.UpdateRotation(controlRotation);
// Ajout pour changer de personnage
if (Input.GetKeyDown(KeyCode.Alpha1)) CharSelection[0].isOn = true;
if (Input.GetKeyDown(KeyCode.Alpha2)) CharSelection[1].isOn = true;
if (Input.GetKeyDown(KeyCode.Alpha3)) CharSelection[2].isOn = true;
if (Input.GetKeyDown(KeyCode.Alpha4)) CharSelection[3].isOn = true;
int ScanNo = 0;
foreach (Toggle thisOption in CharSelection)
{
if (thisOption.isOn)
{
CharToSelect[ScanNo].SetActive(true);
target = CharToSelect[ScanNo].transform;
}
ScanNo++;
}
ScanNo = 0;
foreach (Toggle thisOption in CharSelection)
{
if (!thisOption.isOn)
{
CharSelection[ScanNo].isOn = false;
CharToSelect[ScanNo].SetActive(false);
}
ScanNo++;
}
}
Lignes sautées … … … … … … … …
Bref commentaire :
o On définit les variables Toggle[] et GameObject[] permettant d’afficher les liens.
o On vérifie au démarrage qu’il y ait bien autant de cases à cocher que de personnages (si ce n’est pas
le cas on affiche l’anomalie dans la console mais on stoppe l’exécution.
o Dans la fonction UpDate(), On relie les touches de clavier numérique aux cases à cocher, puis on
Active ou Désactive, en conséquense, les personnages en cours d’exécution.
d) Les personnages sont identiques excepté leur Avatar qui les diférencient :
Ils sont tous animés par le même « Animator Controller », AdvPlayer_Mixamo et le script que nous avons
créé dans l’exercice précédent « Multi_Player_Controller (son nom anticipait, déjà, sur son utilisation
actuelle).
Noter que son composant « Transform » est lié à l’objet Pivot de « Multi_Camera_Rig ».
123
e) Noter qu’il n’est pas nécessaire de relier l’évènementes « OnValueChange » des cases à
cocher à une fonction :
La mise à jour est effectuée , à chaque cycle , par la fonction Update du script
« Multi_Char_CamControl ».
f) Tester le résultat :
124
C’EST AINSI QUE SE TERMINE LE 1erCYCLE DE TUTORIELS, JE DISPOSE DES MOYENS DE
POURSUIVRE, MAIS JE VOUDRAIS, D’ABORD, AVOIR UN RETOUR SUR LA MANIERE DONT
VOUS ACCUEILLEZ CES EXERCICES CAR C’EST, COMME VOUS POUVEZ L’APPRECIER, UN
TRAVAIL LONG ET MINUTIEUX – IL EST, TOUJOURS, PLUS DIFFICILE DE CONCEVOIR DES
EXERCICES PROGRESSIFS ET SIMPLES QUE DE REALISER UN JEU COMPLET.
Les prochaines étapes pourraient être la réalisation d’un jeu de plateformes en 2D et un jeu 3D, ce qui permettrait
d’aborder, la création de décors (avec les addons appropriés), l’interaction avec des ennemis, le combat avec armes,
la collecte d’objets dans un magasin propre au personnage (inventory), le décompte d’un score ainsi que de points
de santé et de vie…
A BIENTÔT… J’ATTENDS VOS COMMENTAIRES ET QUESTIONS …
125